Monthly Archive

Categories

PowerShell

Testing the operating system

Saw a question about testing the operating system and decided that the easiest way was to use the Version property from Win32_OperatingSystem. By easiest I mean least typing and string testing.

 

$os = Get-WmiObject -Class Win32_OperatingSystem

switch ($os.Version) {
{$_ -like '10.0*'} {$osv = "Windows 10"; break}
{$_ -like '6.3*'} {$osv = "Windows 8.1"; break}
{$_ -like '6.2*'} {$osv = "Windows 8"; break}
{$_ -like '6.1*'} {$osv = "Windows 7"; break}
default {$osv = "Unrecognised OS"}
}

$osv

 

I used Get-WmiObject as Windows 7 comes with PowerShell v2 which doesn’t contain the CIM cmdlets. I also restricted the test to supported operating systems.

 

A switch based on the Version property of Win32_OperatingSystem does the hard work. Use a string comparison using –like for the test.

 

Finish by printing the result.

 

If you want to include server operating systems you’ll need to also test the caption property.

To install or not

My recent posts about the NTFSsecurity module drew a comment that the cmdlets in the module couldn’t be used because they’re not installed on every server. This raises the question - to install or not.

Windows systems have a huge array of PowerShell cmdlets available:

- those from the PowerShell team that form the “core” of PowerShell

- other Windows teams such as the Networking and Storage teams

- the modules that come with optional features such as AD, DNS or DHCP

- the RSAT tools – though they overlap with the cmdlets from the optional features

- modules from the PowerShell gallery – some Microsoft and others from the community

- modules from third party vendors

 

What I install on a system depends on what the system is supposed to do and what I need to know about the system.

 

A domain controller probably doesn’t need much extra PowerShell functionality installed as it should a single purpose (I include DNS) system.

Similarly, a dedicated Exchange or SQL Server system doesn’t need much else installed – though I may install the DBAtools on a SQL box.

 

A File server is likely to have a mass of NTFS permissions to work with and the NTFSsecurity module would be very useful.

Jump off / admin servers are where I’d likely to install a lot of functionality that can reach out to other systems.

 

The question to install or not doesn’t have a simple answer - some organizations categorically forbid the installation of external software for instance - as it depends on your organization, your needs and what you want to accomplish.

 

As usual with IT the only answer is – IT DEPENDS!

Get-NTFSAcess

Get-NTFSAcess and Get-NTFSEffectiveAccess are two cmdlets from the NTFSsecurity module.

 

Get-NTFSAcess retrieves the access rights on a folder or file. You can immediately who has what rights and from where the rights are inherited.

 

Get-NTFSEffectiveAccess by contrast shows the rights YOU (the account you’re using to access the data) have to a file or folder.

 

This is far superior to Get-Acl where you have to dig through several layers to get the information.

Get-DiskSpace

The Get-DiskSpace cmdlet from the NTFSsecurity module is useful in that it gives ready calculated percentages of free and used space:

AvailableFreeSpacePercent : 56.73%
AvailableFreeSpaceUnitSize : 270.11 GB
ClusterSize : 4096
DriveName : \\?\Volume{c1c4c5bb-0000-0000-0000-f01500000000}\
TotalSizeUnitSize : 476.1 GB
UsedSpacePercent : 43.27%
UsedSpaceUnitSize : 206 GB
FreeBytesAvailable : 290024239104
TotalNumberOfBytes : 511210610688
TotalNumberOfFreeBytes : 290024239104
BytesPerSector : 512
NumberOfFreeClusters : 70806699
SectorsPerCluster : 8
TotalNumberOfClusters : 124807278

 

BUT as you can see it doesn’t identify the Drive Name by user friendly name.

You can do

PS> Get-DiskSpace -DriveLetter C:

AvailableFreeSpacePercent : 56.73%
AvailableFreeSpaceUnitSize : 270.1 GB
ClusterSize : 4096
DriveName : C:\
TotalSizeUnitSize : 476.1 GB
UsedSpacePercent : 43.27%
UsedSpaceUnitSize : 206 GB
FreeBytesAvailable : 290020270080
TotalNumberOfBytes : 511210610688
TotalNumberOfFreeBytes : 290020270080
BytesPerSector : 512
NumberOfFreeClusters : 70805730
SectorsPerCluster : 8
TotalNumberOfClusters : 124807278

 

but that means passing each drive separately. The DriveLetter parameter should take an array of drives according to the syntax diagram but that doesn’t seem to work.

 

Try running something like

Get-Volume |
where DriveLetter |
sort Driveletter |
foreach {
Get-DiskSpace -DriveLetter "$($_.Driveletter):" |
select DriveName, TotalSizeUnitSize, UsedSpaceUnitSize,
AvailableFreeSpaceUnitSize, UsedSpacePercent, AvailableFreeSpacePercent
}

and you get a nice output

DriveName : C:\
TotalSizeUnitSize : 476.1 GB
UsedSpaceUnitSize : 206 GB
AvailableFreeSpaceUnitSize : 270.1 GB
UsedSpacePercent : 43.27%
AvailableFreeSpacePercent : 56.73%

PowerShell Admin Modules

My PowerShell Admin Modules that used to be available through codeplex are now available on github - https://github.com/RichardSiddaway/PowerShell-Admin-Modules

 

I haven’t updated them since their original publication but they’re still valid

 

Enjoy

PowerShell articles

Here’s some links for other PowerShell articles I’ve written recently

https://searchwindowsserver.techtarget.com/tip/PowerShell-commands-to-copy-files-Basic-to-advanced-methods

https://searchwindowsserver.techtarget.com/tutorial/PowerShell-commands-for-Active-Directory-Groups-management

https://searchwindowsserver.techtarget.com/tip/PowerShell-Core-61-offers-many-small-improvements

https://searchwindowsserver.techtarget.com/tutorial/How-PowerShell-Direct-helps-polish-off-those-VMs

https://searchwindowsserver.techtarget.com/tutorial/Working-with-PowerShell-module-downloads-from-the-gallery

Enjoy

Change file times

When a file is created, accessed or modified that time is recorded. This is how to change file times.

There are three properties to consider:

CreationTime

LastAccessTime

LastWriteTime

 

Just to add to the fun there are UTC (GMT in real world) times as well:

CreationTimeUtc

LastAccessTimeUtc

LastWriteTimeUtc

 

If you need to change a property its a set operation. For instance

Get-ChildItem -Path x9.txt | foreach {$_.LastWriteTime = ($_.LastWriteTime).AddHours(6)}

 

Substitute the appropriate property as required. If you change a property the UTC version is changed in step – accounting for timezone differences

Get first non-repeating character in a string

How do you get first non-repeating character in a string.

 

In Windows PowerShell v5.1 you could use Group-Object but as I showed last time that approach has been taken away in PowerShell v6.1.

 

Instead you need to loop through the characters in the string and count them

function get-firstnonrepeatcharacter {
[CmdletBinding()]
param (
[string]$teststring
)

$a = [ordered]@{}

$teststring.ToLower().ToCharArray() |
foreach {
if ($a.$psitem) {
$a.$psitem += 1
}
else {
$a += @{$psitem = 1}
}

}

$a.GetEnumerator() | where Value -eq 1 | select -First 1

}

 

Input the test string through a parameter. Create an ORDERED hash table for the results – you need to preserve the order in which characters are counted!

 

Convert the string to lowercase (remove this step if your worried about case) and convert to an array of chars. Pipe into foreach-object. Test is the character is already in the hashtable. If it is increment the count. If it isn’t add it.

 

Use the getEnumerator() method to access the hash table. use where-object to filter for characters only appearing once. Select the first one.

 

$ts = 'lcoauywfnqumfheolfzaliigngulxqdbnzprnylfqvsxathrqsyjowm'

PS> get-firstnonrepeatcharacter -teststring $ts

Name Value
----      -----
c          1

Counting vowels

If you’re given a string how would you go about counting vowels, consonants and non-alphabet characters.

 

My approach would be:

 

function measure-vowel {
[CmdletBinding()]
param (
[string]$teststring
)

$counts = [ordered]@{
Vowels = 0
Consonants = 0
NonAlphabet = 0
}

$vowels = 97, 101, 105, 111, 117

$teststring.ToLower().ToCharArray() |
foreach {
$test = [byte]$psitem

switch ($test) {
{$test -in $vowels} {$counts.Vowels += 1; break}
{$test -ge 97 -and $test -le 122} {$counts.Consonants += 1; break}
default {$counts.NonAlphabet += 1; break}
}

}

New-Object -TypeName PSObject -Property $counts

}

 

The string to test is an input parameter. Set up the output hash table and the byte value of the vowels.

 

Convert the string to lowercase and then to a char array which is put on the pipeline. Convert the char to a byte value and then use the switch statement to determine if its a vowel, consonant or non-alphabetic character.

 

Finally output the results.

Create a random string

I often need to create a random string of characters. Here’s a simple function to achieve that:

 

function get-randomstring {
[CmdletBinding()]
param (
[int]$length
)

$rca = 1..$length |
foreach {
$ran = Get-Random -Minimum 97 -Maximum 123
[char][byte]$ran
}

$rca -join ''

}

 

The required length is passed as an integer parameter. Use the range operator as a counter and in Foreach-Object generate a random number between 97 and 122. Convert that to a char (a=97 and z-122) and add to the array. Join the array of chars to create the string.