Social

torsdag den 9. juni 2016

Filtering on NULL in SMLets

No time since I wrote about Service Manager. Something that comes back to haunt me from time to time is filtering on NULL. I always forget how, so now I will document it, once and for all!

A script speaks a thousand words:


1
2
3
4
5
6
7
$IRClass = Get-SCSMClass system.workitem.incident$
# get all IRs where the classification is not set
Get-SCSMObject -Class $IRClass -Filter "Classification -ISNULL"

# if we need to filter on a property from a class extension, specify that exact class
$MyClassExt = Get-SCSMClass incident.extension$
Get-SCSMObject -Class $MClassExt -Filter "CustomerProperty -ISNULL"

tirsdag den 24. maj 2016

Script for deploying Nano Server (TP5)

There are plenty of scripts around that helps deploying Nano server. But there seems to be issues between the various TPs, I had trouble with a script that worked for TP4 but not at all for TP5.

So I ended up creating my own. It should just run in one go, but I suggest you take a few lines at at time to sort out any issues.

The script as follows, and found on Technet gallery.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# note this is written for Server 2016 TP5 - it probably doesn't work on other TPs

# create this folder and copy the NanoServerImageGenerator from the 2016 media
cd D:\NanoServer

Import-Module .\NanoServerImageGenerator\NanoServerImageGenerator.psm1


$BasePath = "D:\NanoServer"
$TargetPath = "$BasePath\Nano01.vhd"
$ComputerName = "Nano01"
$Password = ConvertTo-SecureString -AsPlainText -String "Password" -Force

$IPAddress = "192.168.0.42"
$GatewayAddress = "192.168.0.1"
$DNSAddresses = ('192.168.0.21','8.8.8.8')
$Ipv4SubnetMask = "255.255.255.0"

$Domain = 'my.domain'

$Parameters = @{
    DeploymentType = 'Guest'
    Edition = 'Datacenter'
    MediaPath = "E:\"
    BasePath = $BasePath
    TargetPath = $TargetPath
    ComputerName = $ComputerName
    AdministratorPassword = $Password
    Ipv4Address = $IPAddress
    Ipv4SubnetMask = $Ipv4SubnetMask
    Ipv4Gateway = $GatewayAddress
    Ipv4Dns = $DNSAddresses
    InterfaceNameOrIndex = "Ethernet"
}

New-NanoServerImage @Parameters -ErrorAction Stop

# credentials for the nano server
$User = "$IPAddress\Administrator"
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $Password

# add it to trusted hosts
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $IPAddress -Force -Concatenate

# size of the vhd - WOW!
[int]((Get-ChildItem -Path $TargetPath).Length / 1MB)

# can only install IIS and SCVMM offline
Find-NanoServerPackage *iis* | Install-NanoServerPackage -Culture 'en-us' -ToVhd $TargetPath -Verbose
Find-NanoServerPackage *scvmm* | Install-NanoServerPackage -Culture 'en-us' -ToVhd $TargetPath -Verbose

# create a new VM
$VMName = "Nano01"
New-VM -Name $VMName -MemoryStartupBytes 512MB -SwitchName MGMT -VHDPath $TargetPath -Generation 1 -Verbose

# and start it
Start-VM -Name $VMName

# we wait - first boot can be "slow" :D
Write-Verbose "waiting abit for VM to boot for the first time..."
Start-Sleep -Seconds 20

# need to run this with administrative priviliges in the domain
djoin.exe /provision /domain $Domain /machine $ComputerName /savefile .\"$ComputerName.txt"

# create session object
$Session = New-PSSession -ComputerName $IPAddress -Credential $Credential

# copy domain join blob file to nano server
Copy-Item -ToSession $Session -Path .\"$ComputerName.txt" -Destination "c:\"

# enter the session
Enter-PSSession -Session $Session

# domain join nano server
djoin /requestodj /loadfile c:\$env:COMPUTERNAME.txt /windowspath c:\windows /localos

# and do a restart
Restart-Computer

# wait for restart

# need to create a new session after it restarts - and we will use domain credentials
$User = "$Domain\Administrator"
$Password = ConvertTo-SecureString "domainadminpassword" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $Password

$Session = New-PSSession -ComputerName $IPAddress -Credential $Credential

# enter the session
Enter-PSSession -Session $Session

# install the nano server package provider

Install-PackageProvider NanoServerPackage
Import-PackageProvider NanoServerPackage

Find-NanoServerPackage

mandag den 2. maj 2016

Automated module installation to Azure Automation

Ever needed to install a bunch of modules to an Azure Automation Account? This script can do it for you. Only thing you need to do is point it at the ARM-template that deploys the module. These templates are easy to obtain by following the description in the script-file. A simple loop can install multiple modules (example on how in the file).

Get it while it's hot.

tirsdag den 26. april 2016

Generate ARM template parameter file

I find it tedious to create parameter files for my ARM templates. With the script I just wrote you don't have to.

Simply point at the ARM template that you need a parameter file for, and the function will spit out the json that matches. Pipe it to Out-File or "clip" to put it in your clipboard and paste it into Visual Studio or other ARM template editor of choice.

Go grab it here - remember to rate if you like it :D

onsdag den 21. oktober 2015

Pinging with Powershell - Get a list of online servers

Just about every IT guy or girl on the planet has used ping countless of times. With Powershell those days are over: Meet Test-Connection. It works just as you would expect and similar to ping, the advantage being that you (by default) get an object of type "System.Management.ManagementObject#root\cimv2\Win32_PingStatus" back.

I wont go into details on how to use Test-Connection, there are plenty of ressources doing just that. But I recently discover a very cool way to use Test-Connection against a large number of servers. And as they say, A script is worth a thousand words:

function Check-Online
{
    param(
        $ComputerName
        )

    Begin
    {
        # put live servers into this list
        $Script:serverlist = @()
    }

    Process
    {
        If (Test-Connection -Count 1 -ComputerName  $_ -TimeToLive 5 -asJob | 
         Wait-Job |
         Receive-Job |
         ? { $_.StatusCode -eq 0 } )
        {
            $Script:serverlist += $_
        }
    }
    End
    {
        return $Script:serverlist
    }
}

# get computer names from hyper-v
$ComputerNames = Get-VM | Select-Object -ExpandProperty Name
# check which are online
$ComputerNames | Check-Online

Simply feed the Check-Online function a list of computernames (IPs should work just as well) and it will return a list of online servers within seconds.

I think credit for the original code goes to my Lumagate colleague Claus Nielsen who just happens to be a Powershell MVP.

Download script from Technet gallery.

fredag den 16. oktober 2015

Reattaching Drives on VMs Using Powershell (General access denied on vhdx)

I recently had some storage issues in the company lab which meant that after a lengthy CHKDSK that permission on all VHDX files was lost. The solution was luckily simple: Reattach each drive and the permission on the file was restored. Problem was then that there was more than 50 drives all in all. Solution then became, as it often is, do it with Powershell.

The script as follows (Download from Technet), formatted using https://tohtml.com/powershell/:

$States = ( [Microsoft.HyperV.PowerShell.VMState]::Off, 
            [Microsoft.HyperV.PowerShell.VMState]::OffCritical
          )

$VMs = Get-VM | ? {$_.State -in $States}
$DriveCount = ($VMs | Get-VMHardDiskDrive).Count
$Counter = 0

foreach($VM in $VMs)
{
    $Drives = $VM | Get-VMHardDiskDrive
    foreach($Drive in $Drives)
    {
        $Counter += 1
        # Some of these values (Path at least) disappear from the $Drive object when we remove it from the machine
        $ControllerNumber = $Drive.ControllerNumber
        $ControllerLocation = $Drive.ControllerLocation
        $Path = $Drive.Path
        $SupportPersistentReservations = $Drive.SupportPersistentReservations
        $ControllerType = $Drive.ControllerType

        Write-Progress  -Activity "Reattaching drives" `
                        -Status "Removing $Path from $($VM.Name)" `
                        -PercentComplete (100*$Counter/$DriveCount) 
        Remove-VMHardDiskDrive -VMHardDiskDrive $Drive
        
        if($SupportPersistentReservations)
        {
            # Shared vhdx
            Add-VMHardDiskDrive -VM $VM `
                                -ControllerNumber $ControllerNumber `
                                -ControllerLocation $ControllerLocation `
                                -Path $Path `
                                -ControllerType $ControllerType `
                                -SupportPersistentReservations
        }
        else
        {
                        Add-VMHardDiskDrive -VM $VM `
                                -ControllerNumber $ControllerNumber `
                                -ControllerLocation $ControllerLocation `
                                -Path $Path `
                                -ControllerType $ControllerType
        }
        
        Write-Progress  -Activity "Reattaching drives" `
                        -Status "Reattached $Path to $($VM.Name)" `
                        -PercentComplete (100*$Counter/$DriveCount)
    }
}

tirsdag den 6. oktober 2015

Creating Multiple Azure NICs Using Multiple Instances (ARM Template)

I have started playing around with ARM and Azure in general and wanted to get my feet wet with linked templates and multiple instances. My very gifted colleague Kristian Nese has already covered template linking just fine, but I have yet to find a simple example on how to use multiple instances (honestly, I didn't try that hard, I want to do it myself).

Anyways, I thought I would share what I have done so far. It is a good introduction to multiple instances in ARM templates, and also get to use a few of the template functions. I will not provide a full solution (strongly suggest you piece it together yourself for the learning experience), but rather snippets and explanations (to the best of my knowledge).

If you are new to ARM templates: go away. No, just kidding, but do come back when you have the basics covered. I attended this hands on lab recently and found the excercises was an excellent learning experience. The teacher suggested not to use Visual Studio as you miss out on learning some of the basics of ARM templates. Follow that advice and just use your prefered json-editor (Sublime Text 2).

We will jump right in. The following snippet creates multiple NICs in Azure based on a parameter namePrefixes which we use to prefix various resources.

"namePrefixes": {
      "type": "array",
      "defaultValue": [
        "dc",
        "sql",
        "scsm"
      ]
    }

The resource NICs are declared as follows

{
  "dependsOn": [
    "[concat('Microsoft.Resources/deployments/',  parameters('vnetName'))]",
    "[concat('Microsoft.Network/publicIPAddresses/', parameters('namePrefixes')[copyIndex()], '-', variables('pulicIPPostfix'))]"
  ],
  "name": "[concat(parameters('namePrefixes')[copyIndex()], '-', variables('nicPostfix'))]",
  "type": "Microsoft.Network/networkInterfaces",
  "location": "[resourceGroup().location]",
  "apiVersion": "2015-06-15",
  "copy": {
    "name": "nicCopy",
    "count": "[length(parameters('namePrefixes'))]"
  },
  "properties": {
    "ipConfigurations": [
      {
        "name": "[concat('ipconfig', copyIndex())]",
        "properties": {
          "privateIPAllocationMethod": "static",
          "privateIPAddress": "[concat(variables('addressPrefixSplit')[0], '.', variables('addressPrefixSplit')[1], '.', variables('addressPrefixSplit')[2], '.', add(copyIndex(), 4))]",
          "subnet": {
            "id": "[variables('subnetID')]"
          },
          "publicIPAddress": {
            "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('namePrefixes')[copyIndex()], '-', variables('pulicIPPostfix')))]"
          }
        }
      }
    ]
  }
}

First we need to indicate that the nics depend on a virtual network. Here I am using Microsoft.Resources/deployments because the virtual network has been deployed using a linked template. We also depend on some public ip addresses that we have created using multiple instances also.
The naming scheme is to iterate the namePrefixes array and postfix the variable nicPostfix (mine has the value "nic").
Now in order to provide static IP addresses we use the variable addressPrefixSplit which is defined as

"addressPrefixSplit": "[split(parameters('addressPrefix'), '.')]"


We simply split the addressPrefix parameter on '.', ex. 10.0.0.0/16 which is also used to create the virtual network. The IP address is then the first 3 octets of the addressPrefix and the 4th octet is the value of copyIndex() + 4 which would give us the addresses: 10.0.0.4, 10.0.0.5, and 10.0.0.6.

The public IP Address is a reference to the resource ID of public IP addresses created using the same approach:

{
      "apiVersion": "2015-06-15",
      "type": "Microsoft.Network/publicIPAddresses",
      "location": "[resourceGroup().location]",
      "name": "[concat(parameters('namePrefixes')[copyIndex()], '-', variables('pulicIPPostfix'))]",
      "copy": {
        "name": "pipCopy",
        "count": "[length(parameters('namePrefixes'))]"
      },
      "properties": {
        "publicIPAllocationMethod": "[variables('publicIPAllocationMethod')]"
      }
}

Now you are ready to deploy a billion trillion NICs with just a few lines of json (not counting the billion trillion lines of name prefixes :D)

Søg i denne blog

Indlæser...