Putting comments into your code has been a long established practice – this is how you do PowerShell comments
A single line comment is indicated by the # symbol
# This is a comment
You can put a comment at the end of a line but not in the middle. Once you’ve added a comment that’s it for the rest of the line
Get-Process # This is a comment
In ISE and Visual Studio Code comments are shown in green by default
You can also create multi-line comments
Be careful if you use # symbols in file names or other data in PowerShell – you may end up with PowerShell thinking you’ve declared a comment
Microsoft has announced a continuous updates expansion at Ignite
Windows 10 was always going to be continually updated rather than new versions introduced.
This year Windows Server 2016 joined the party when it was announced that there would be twice yearly updates – Windows 10 moved to the same cadence.
At Ignite Microsoft announce that a number of other products would join the continuous update party including:
Office 2019 – should see it in second half of 2018
Skype for Business
Assuming they join the twice yearly updates – NOTE these are not patches but new features or changes – cadence that the OS teams have adopted this is going to bring interesting times for operations staff.
On the plus side the need to roll out completely new builds of workstations goes away because you’re not going to get a new OS in a few years.
On the negative side you’re going to have to develop a strategy for dealing with new feature releases on a perhaps twice yearly basis, You can put off, for a time, these particular updates but life will start to get very messy very quickly unless you freeze all feature updates. – Bet your users will be clamouring for the updated features.
This change is 1-2 years off but you need to start thinking about how you’re going to handle it NOW otherwise you’ll have a very complicated environment that becomes more difficult to manage with time.
Saw an interesting question on splitting multiline string
If you get a set of strings
emailed to you then you could put them in a text file and use Get-Content to read them into an array. The question was could you paste them into PowerShell and get the same effect.
Not sure if this is the easiest way but it works
PS> $x = @’
‘@ -split “`n”
A number of my PowerShell books including PowerShell in Action and PowerShell in Depth will be part of Manning’s Deal of the Day on 29 September 2017
Use code dotd092917au at https://bit.ly/2hzetVX
For DoD details see https://www.manning.com/dotd
Following my last post I was asked about these Examples of replacing WMI cmdlet with CIM cmdlet.
gwmi win32_operatingsystem -computername $Computer -credential $creds,
$cs = New-CimSession -Credential $creds -ComputerName $computer
Get-CimInstance -ClassName Win32_operatingsystem -CimSession $cs
get-wmiobject -query “SELECT * FROM Meta_Class WHERE __Class = ‘Win32_Process’” -namespace “root\cimv2” -computername $computer -credential $creds
$cs = New-CimSession -Credential $creds -ComputerName $computer
Get-CimInstance -Query “SELECT * FROM Meta_Class WHERE __Class = ‘Win32_Process’” -CimSession $cs
Get-WmiObject -Namespace $namespace -Class SMS_fullcollectionmembership -ComputerName $SCCMServer -filter “Name = ‘$computer’” -credential $creds
$cs = New-CimSession -Credential $creds -ComputerName $SCCMServer
Get-CimInstance -Namespace $namespace -ClassName SMS_fullcollectionmembership ” -filter “Name = ‘$computer’” -CimSession $cs
I still see a lot of people using the WMI cmdlets – Get-WmiObject etc. You really should be using CIM nit WMI. In other words use Get-CimInstance rather than get-WmiObject etc etc.
Why do I say that?
Two main reasons.
Firstly, the WMI cmdlets are effectively deprecated. Any further development effort will be for the CIM cmdlets.
Secondly, and to my mind more important, is that the CIM cmdlets use WS-MAN for access to remote machines. If you have PowerShell remoting enabled you have access to the machine via a CIM session – either ephemeral using the cmdlet name or persistent using a CIM session.
The WMI cmdlets use DCOM for remoting which is blocked by default on the Windows firewall and most other firewalls and routers giving the RPC server is unavailable error.
The only time there is justification for using the WMI cmdlets is if you’re on a machine that has Powershell v2 installed and if that’s the case why haven’t you upgraded? If you can’t does that mean you’re running an application (usually Exchange or System Center) that doesn’t allow you to upgrade PowerShell.
Maybe its time to perform that upgrade.
As another thought PowerShell v6 includes the CIM cmdlets but not the WMI cmdlets!
PowerShell is all about working with objects but sooner or later you’ll need to write text to a file with Powershell.
You have two options. The *-Content cmdlets and Out-File
PS> Get-Command *-Content CommandType Name ----------- ---- Cmdlet Add-Content Cmdlet Clear-Content Cmdlet Get-Content Cmdlet Set-Content PS> Get-Command *-File CommandType Name ----------- ---- Cmdlet Out-File Cmdlet Unblock-File
Lets start with Out-File
Out-File simply sends output to a file. Its the equivalent of the redirection operator but with parameters.
PS> Get-Process -Name power* | Out-File -FilePath gp1.txt PS> Get-Content gp1.txt Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 672 33 124272 144548 1.88 6112 1 powershell 767 31 86756 105336 2.64 11984 1 powershell
Whatever comes down the pipeline is redirected to the specified file instead of being displayed on screen.
By default Out-File (like redirection) will overwrite an existing file. You can append data to the file
PS> Get-Process -Name power* | Out-File -FilePath gp1.txt -Append PS> Get-Content gp1.txt Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 672 33 124272 144548 1.88 6112 1 powershell 767 31 86756 105336 2.64 11984 1 powershell Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 673 33 124272 144580 1.88 6112 1 powershell 798 32 73980 92564 2.64 11984 1 powershell
To protect an existing file that you don’t want overwriting IF it exists use the –NoClobber parameter
PS> Get-Process -Name power* | Out-File -FilePath gp1.txt -NoClobber Out-File : The file 'C:\test\gp1.txt' already exists. At line:1 char:28 + Get-Process -Name power* | Out-File -FilePath gp1.txt -NoClobber + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceExists: (C:\test\gp1.txt:String) [Out-File], IOException + FullyQualifiedErrorId : NoClobber,Microsoft.PowerShell.Commands.OutFileCommand
You can overwrite a read only file with the –Force parameter.
By default Out-File uses unicode encoding. Other encodings are available
This will be important if the file will be read by something other than PowerShell.
The *-Content cmdlets are different in that they expect strings
PS> Get-Process -Name power* | Set-Content -Path gp2.txt PS> Get-Content -Path gp2.txt System.Diagnostics.Process (powershell) System.Diagnostics.Process (powershell)
Set-Content and Add-Content use ASCII encoding by default. The other encodings are available
ASCII Uses the encoding for the ASCII (7-bit) character set.
BigEndianUnicode Encodes in UTF-16 format using the big-endian byte order.
BigEndianUTF32 Encodes in UTF-32 format using the big-endian byte order.
Default Encodes using the default value: ASCII.
Byte Encodes a set of characters into a sequence of bytes.
String Uses the encoding type for a string.
Unicode Encodes in UTF-16 format using the little-endian byte order.
UTF7 Encodes in UTF-7 format.
UTF8 Encodes in UTF-8 format.
Unknown The encoding type is unknown or invalid; the data can be treated as binary.
We can modify our previous example
PS> Get-Process -Name power* | Out-String | Set-Content -Path gp2.txt PS> Get-Content -Path gp2.txt Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 627 34 156396 177492 3.00 6112 1 powershell 726 32 71640 91540 3.17 11984 1 powershell
Set-Content will overwrite the content of a file or create a new file. Add-Content appends data to a file
PS> Get-Process -Name power* | Out-String | Add-Content -Path gp2.txt PS> Get-Content -Path gp2.txt Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 627 34 156396 177492 3.00 6112 1 powershell 726 32 71640 91540 3.17 11984 1 powershell Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 676 34 156436 177648 3.05 6112 1 powershell 744 32 71604 91540 3.27 11984 1 powershell
The help files for these cmdlets show so other examples.
NOTE: In PowerShell v6 the encodings will be standardised.
When we talk about heterogeneous environments the assumption is that we mean a mixture of Windows and Linux machines. Windows and Linux can be viewed as providing the end points of a spectrum of management issues. In reality there is another spectrum – that spectrum exists between Windows machines.
Thinking ONLY of server administration you could easily have Windows 2008, Windows 2008 R2, Windows 2012, Windows 2012 R2 and Windows 2016 servers in your environment. And that’s only the supported operating systems. From experience I’d expect that many organisations still have Windows 2003 servers and I suspect there are still some Windows 2000 servers in quite a few organisations. I wouldn’t be shocked to find a few Windows NT machines still in use!
The five supported Windows Server OSs are bad enough. Windows 2016 is moving to twice yearly updates starting this autumn (that’s fall for non-English readers). Windows 2008 & 2008 R2 go out of mainstream support in 2020 so giving the option for 5 versions of 2016 to be released before it vanishes. The Server 2012 family is supported until October 2023!
The point is that you need to think how you’re going to support a potentially large number of operating system editions going forward. I seriously doubt that anyone will be updating their whole server estate on a twice yearly basis.
Multiple small releases enable updates to particular areas of Windows being released quickly. So one release may update Hyper-V while another updates containers or storage.
Working out which Windows builds – and you will have to start thinking at the build level – will support particular versions of Exchange, SQL Server, SharePoint or any of the other Microsoft products. Expect other vendors of software that runs on top of windows server to panic when you ask them about supporting particular builds – they’re usually so slow at supporting new versions that the next is in beta. That behaviour is going to cause issues.
You could avoid some of this by saying you’ll skip builds – 1, 2, 3 or X years worth – but what happens when a new feature fixes a problem you’ve got now!
Heterogeneity is going to become more widespread. On the plus side it may kill the option of whole sale upgrades and massive server migration projects. You’ll just be permanently upgrading!
At the moment its not too big an issue but I expect over time that you’ll need to think about build number
PS> Get-CimInstance -ClassName win32_operatingsystem | select -ExpandProperty BuildNumber
as much as version
PS> Get-CimInstance -ClassName win32_operatingsystem | select -ExpandProperty Version
And that’s before we get to Linux.
If you’re writing scripts that do different things based on Windows version think about dropping down to build number as well. You can always use a –gt <build number> approach.
You’re going to be living in interesting times.
Strings – a list of characters such as ‘abcd’ – are a common feature of programming or scripting. Sometimes you need to join – concatenate – two or more strings together. This is how PowerShell string concatenation works.
First you need to know that strings can be defined with single quotes or double quotes:
PS> $sq = ‘A single quoted string’
A single quoted string
PS> $dq = “A double quoted string”
A double quoted string
The difference is that you can substitute into a double quoted string. Best practice is to use single quotes UNLESS you intend to substitute into the string
PS> ‘I am $sq’
I am $sq
PS> “I am $sq”
I am A single quoted string
String concatenation can be performed using the concatenation operator – a plus sign or through string substitution
PS> $s1 = ‘abcd’ + ‘defg’
You can use variables
PS> $s1 = ‘abcd’
PS> $s2 = ‘defg’
PS> $s3 = $s1 + $s2
When you concatenate strings like this you’re actually creating a new string not extending an existing one.
Alternatively, use string substitution
PS> $s4 = “$s1$s2”
PowerShell has operators – lots of operators. So many operators that it took us TWO chapters to work through them all in PowerShell in Action, third edition – https://www.manning.com/books/windows-powershell-in-action-third-edition. Here’s how you can discover the PowerShell operators.
PS> Get-Help about*operator*
A quick listing gives us:
Arithmetic operators (+, -, *, /, %)
Assignment operators (=, +=, -=, *=, /=, %=)
Comparison operators (-eq, -ne, -gt, -lt, -le, -ge) (-match, -notmatch) (-like, -notlike)
(-in, -notin, -contains, -notcontains) (-bAND, -bOR, -bXOR, -bNOT)
Logical opertors (-and, -or, -xor, -not, !)
Redirection operators (>, >>, 2>, 2>, and 2>&1)
Type operators (-is, -isnot, -as)
And a bunch of special operators @(), & (call),  (cast), comma, dot, –f , index opertor, pipeline operator, range operator, :: static member operator, $()
Also don’t forget –split, –join, –replace