Tuesday, May 24, 2016

Copy Over PowerShell Remoting Sessions

You can use PowerShell remoting to transfer files across a network – this is new in PowerShell 5.0.

This can be useful in closed environments where you have no SMB file shares. It is not very efficient (and slow) though. Here is an example:

# Create a session to the target computer (assuming you have set up PowerShell remoting before)
$session = New-PSSession -ComputerName dc-01
# Copy a file from the target to your computer
# Specify the local path for the file on the target system
Copy-Item -FromSession $session -Path C:\windows\DPINST.LOG -Destination C:\test

Twitter This Tip! ReTweet this Tip!

Monday, May 23, 2016

One-Liner Random Password Generator

Check out this simple way of creating temporary passwords:

-join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ23456789$%&*#'.ToCharArray() | Get-Random -Count 8)

You can easily vary the password length: change the number for -Count to whatever password length you need.

Twitter This Tip! ReTweet this Tip!

Saturday, May 21, 2016

Android & Offroad...



Coming to off-roading from a technological background, always thought should do something to my off-road tool – Toyota FJ…

 

In the past I have successfully mounted a carputer (Car Computer) in a BMW, something that took a good part of the year, but something I loved. Technology has changed over the years, what was not possible few years ago is possible now.

 

Like an android unit, with more juice that yester-year desktop computers, integration available now makes it more interesting to work something out.

 

With all that I set off to setup android in my FJ, idea was simple, all the stuff I need should be there, mounted nicely.

 

Starting with following requirements (simple stuff) but one objective, centralization…

  1. Navigation – On/Off Road
  2. Action camera
  3. Wi-Fi Internet
  4. OBD (On Board Diagnostics)

 

Few weeks homework and I came up with thoughts of Android ticking all the boxes, but then there is no good android head units out there that would fit the bill.

 

Finally found a head unit off my favorite site … AliExpress.Com … with a price tag that I am willing to pay (<>$300).

Stay tuned for  more...

Friday, May 20, 2016

Harvesting Reboot Time from EventLog

In the previous tip we illustrated how you can ask WMI for the last reboot time of a machine. A more robust way is to query the Windows event logs. Here is how:

# get the latest reboot event from the System event log
$e = Get-EventLog System -Source Microsoft-Windows-Kernel-General -InstanceId 12 -Newest 1 
# read time information from collection of event info
$e.ReplacementStrings[-1]
# turn info in DateTime
$reboot = [DateTime]$e.ReplacementStrings[-1]
$reboot
"System was last rebooted: $reboot"
$timespan = New-TimeSpan -Start $reboot
$days = $timespan.Days
"System is running for more than $days days."

Each event has a very helpful property called ReplacementStrings. This array is full of event information. You would need to determine the meaning of the array elements yourself, but once you figure that out, it is always the same for an instance ID. In the example, the last element in ReplacementStrings (index -1) is always the reboot time.

The reboot time is stored in a cryptic management format. Simply cast it to DateTime though to make it readable.

Twitter This Tip! ReTweet this Tip!

Thursday, May 19, 2016

Last Bootup Time with Get-CimInstance

These days, computers hibernate or go into standby but do not really reboot that often anymore. To find out when your computer rebooted the last time, try this line in PowerShell 3.0 or better:

Get-CimInstance -Class Win32_OperatingSystem  |  
  Select-Object -ExpandProperty LastBootupTime

In older PowerShell versions, there is no Get-CimInstance, and you would have to resort to the simple Get-WmiObject cmdlet:

Get-WmiObject -Class Win32_OperatingSystem |  
  Select-Object -ExpandProperty LastBootupTime

One of the disadvantages of Get-WmiObject is that it does not return DateTime objects but instead its own WMI date and time format:

 
20160420070403.496011+120
 

Twitter This Tip! ReTweet this Tip!

Wednesday, May 18, 2016

Extracting Text Information

Tracert.exe tells you the hops your data packages need to take to get to a given host. Here is an example:

 
PS C:\> tracert www.microsoft.com

Tracing route to e10088.dspb.akamaiedge.net [2.16.194.227]
over a maximum of 30 hops:

  1     8 ms     8 ms     9 ms  1st.railnet.train [10.204.90.1] 
  2    55 ms    47 ms    48 ms  ntp3.railnet.core [10.10.128.1] 
  3    61 ms    68 ms    51 ms  10.64.17.193 
  4   176 ms   160 ms   240 ms  10.64.21.37 
  5     *        *        *     Request timed out.
  6  2019 ms  1724 ms   942 ms  10.64.23.37 
  7     *        *        *     Request timed out.
  8     *        *        *     Request timed out.
  9     *        *        *     Request timed out.
 10     *      499 ms   713 ms  193.159.166.50 
 11  1864 ms  2370 ms     *     a2-16-194-227.deploy.akamaitechnologies.com [2.16.194.227] 
 12  3199 ms  3787 ms     *     a2-16-194-227.deploy.akamaitechnologies.com [2.16.194.227] 
 13     *        *        *     Request timed out.
 14     *        *        *     Request timed out.
 15  1173 ms     *     2522 ms  a2-16-194-227.deploy.akamaitechnologies.com [2.16.194.227] 

Trace complete.
 

If you were just interested in the names of the hops your packages took, what would you do?

One way is to count the number of characters that you want to ignore per line. In our example, the first 32 characters per line should be ignored. Here is how:

 
PS C:\>  $route = tracert www.microsoft.com  
PS C:\>  $route.Foreach{$_.SubString(32)} 
 
maiedge.net  [2.16.194.227]
1st.railnet.train  [10.204.90.1] 
ntp3.railnet.core  [10.10.128.1] 
10.64.17.193 
10.64.21.37 
Request timed out.
10.64.23.37 
Request timed out.
Request timed out.
Request timed out.
193.159.166.50 
a2-16-194-227.deploy.akamaitechnologies.com  [2.16.194.227] 
a2-16-194-227.deploy.akamaitechnologies.com  [2.16.194.227] 
Request timed out.
Request timed out.
a2-16-194-227.deploy.akamaitechnologies.com  [2.16.194.227]
 

Note that the Foreach() method was introduced in PowerShell 3.0. Use a pipeline with ForEach-Object in older PowerShell versions.

Twitter This Tip! ReTweet this Tip!

Tuesday, May 17, 2016

Bulk-Convert to String

Sometimes, commands and methods do not return exactly what you are after. If you, for example, wanted to get the assigned IP addresses for a hostname, you could try this:

[System.Net.DNS]::GetHostByName('microsoft.com').AddressList

You do get the IP addresses, but they are part of a larger object. The result looks like this:

 
Address            : 601041000
AddressFamily      : InterNetwork
ScopeId            : 
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 104.40.211.35

(...)

Address            : 4223871848
AddressFamily      : InterNetwork
ScopeId            : 
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 104.43.195.251 
 

If you convert the output to a string, however, you get what you want:

[System.Net.DNS]::GetHostByName('microsoft.com').AddressList | 
ForEach-Object { "$_" }

Converting objects to strings can be a last resort if you can’t see another way of getting to the information you are after. The result now looks like this:

 
104.40.211.35
191.239.213.197
23.96.52.53
23.100.122.175
104.43.195.251 
 

And here are the two power tips: if you get too much data from a command, identify the name of the information you are after, and add this with a “.”. So you can get to the IP addresses much more elegantly like this:

[System.Net.DNS]::GetHostByName('microsoft.com').AddressList.IPAddressToString

(The latter technique may require at least PowerShell 3.0, though).

If you must convert all elements to a string, rather than adding a cumbersome ForEach-Object loop, “abuse” the -replace operator like this:

[System.Net.DNS]::GetHostByName('microsoft.com').AddressList -replace ''

The operator does not replace anything. It just converts all incoming data into strings.

Twitter This Tip! ReTweet this Tip!

Monday, May 16, 2016

Create Local Admin Accounts

There is no module available for all PowerShell versions that allows to administer local user accounts. Here is a chunk of sample code that illustrates how you nevertheless can automate local account management.

The code creates a new local Administrator account with password. Provided you have sufficient privileges, you can run the script locally as well as remotely:

# where do you want to create the local admin account?
$ComputerName = $env:COMPUTERNAME
# what is the name of the local admin group?
# WARNING: MUST EXIST! MAY BE DIFFERENT IN DIFFERENT LOCALES
$Group = 'Administrators'
# what is the name of the new account?
$Name = 'ServiceAdmin'
# what is the password?
$Password = 'topSecret123'
# what is the description?
$Description = 'Automatically generated local account'

$computer = [ADSI]"http://WinNT$($ComputerName),computer"
$user = $computer.Create('User', "$($Name)")
$user.SetPassword($password)
$user.Put('Description',$($Description))    
$user.SetInfo()

# password never expires
$user.UserFlags.value = $user.UserFlags.value -bor 0x10000
$user.CommitChanges()

# add user to group
$group = [ADSI]"http://WinNT$($computername)/$($groupname),group" 
$group.add("http://WinNT$($Name),user")

Many other management tasks, such as removal of local groups or change of password, can be accomplished in a similar way.

Twitter This Tip! ReTweet this Tip!

Friday, May 13, 2016

Loops and Arrays (and some surprises)

Frequently, loops are used to retrieve (or generate) data, then save it to a variable. There can be tremendous performance differences though. To generate 10.000 random numbers, for example, you might look into something like this:

$numbers = @()

for ($x = 1; $x -le 10000; $x++) 
{
  $numbers += Get-Random -Minimum 1 -Maximum 7
}

$numbers.Count

It takes many seconds, and becomes almost paralyzing with even larger loop iterations.

Here is a similar approach that is many times faster:

Here is a similar approach that is many times faster:
$numbers = for ($x = 1; $x -le 10000; $x++) 
{
  Get-Random -Minimum 1 -Maximum 7
}

$numbers.Count

Instead of saving the results to a variable with each iteration, leave it to PowerShell to create and maintain the array. Just save the results of the loop when it is done.

Twitter This Tip! ReTweet this Tip!

Thursday, May 12, 2016

Finding Top 3 (of anything)

Ever wanted to know who are the three worst sources for errors in your System event log? Here is a simple approach that yields the source names with the most errors:

Get-EventLog -LogName System -EntryType Error | 
  Group-Object -Property Source |
  Sort-Object -Property Count -Descending |
  Select-Object -First 3 -Property Count, Name

Key is the use of Group-Object: this cmdlet groups items by a property. All error events are grouped by source. Next, the groups are sorted by size, and the three largest groups are returned.

This works with many things. Here are the top 3 file types in your Windows folder (add -Recurse to search the entire tree):

Get-ChildItem -Path $env:windir | 
  Group-Object -Property Extension -NoElement | 
  Sort-Object -Property Count -Descending | 
  Select-Object -First 3

And these are the three most frequent numbers in a series of numbers:

$numbers = for ($x = 1; $x -lt 1000; $x++) 
{
  Get-Random -Minimum 1 -Maximum 7
}

$numbers | 
  Group-Object | 
  Sort-Object -Property Count | 
  Select-Object -First 3 -ExpandProperty Name

Twitter This Tip! ReTweet this Tip!