<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Fernando Rubio´s Microsoft Technet Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/fernandorubio/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/fernandorubio/feed.xml</link>
    <description>Making the digital world a safer place, one post at a time</description>
    <lastBuildDate>Tue, 16 Apr 2019 06:06:13 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Getting the configured Backup on Windows Server 2008 R2 machines remotely using powershell</title>
      <link>https://docs.microsoft.com/archive/blogs/fernandorubio/getting-the-configured-windows-server-backup-on-windows-server-2008r2-machines-remotely-using-powershell</link>
      <pubDate>Wed, 27 Jun 2018 09:17:47 GMT</pubDate>
      <dc:creator><![CDATA[Fernando Rubio Roman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/fernandorubio/?p=125</guid>
      <description><![CDATA[Hi

Sometimes you need to solve a problem in downlevel O.S where the commandlets for the task you...]]></description>
      <content:encoded><![CDATA[Hi

Sometimes you need to solve a problem in downlevel O.S where the commandlets for the task you want are not available. Today was one of these days, one customer asked me… ¿how can I know if I configured properly a bare metal backup of all my 2008r2 domain controllers? Let see how we did it in a quick and dirty (but working way)

First we used the parallexecution module, if you do not know what this is look here: <a href="https://blogs.technet.microsoft.com/fernandorubio/2018/01/25/powershell-remoting-made-easy-with-parallelexecution-module/">https://blogs.technet.microsoft.com/fernandorubio/2018/01/25/powershell-remoting-made-easy-with-parallelexecution-module/</a>

to get using wbadmin the list of backups performed on all the domain controllers in the forest

$domains=(Get-ADForest).domains

$dcs=@()

foreach ($domain in $domains){

$dcs+=get-addomaincontroller -filter * -server $domain

}

$dcnames = $dcs| Select -ExpandProperty hostname

$results=$dcnames | start-parallelexec -command "wbadmin get versions" -Verbose

&nbsp;

This is great, the info we want is there but the result of wbadmin is text we need to parse so we iterate the hashtable, creating an array of tempobjects (one per each backup per DC) and add it as a new custom property to the hashtable.

&nbsp;

foreach ($dc in $results.GetEnumerator()){

$text=$dc.Value.results

$textlenght=$text.Count

$backuparray=@()

for ($i=3;$i -lt $textlenght;$i=$i+$depends){

$tempobject=New-Object -TypeName psobject

$tempobject | Add-Member -MemberType NoteProperty -Name "backuptime" -Value $text[$i]

$tempobject | Add-Member -MemberType NoteProperty -Name "backuplocation" -Value $text[$i+1]

$tempobject | Add-Member -MemberType NoteProperty -Name "versionidentifier" -Value $text[$i+2]

$tempobject | Add-Member -MemberType NoteProperty -Name "contents" -Value $text[$i+3]

$tempobject | Add-Member -MemberType NoteProperty -Name "computername" -Value $dc.Key

if ($text[$i+4] -ne ""){

$tempobject | Add-Member -MemberType NoteProperty -Name "snapshotid" -Value $text[$i+4]

$depends="6"

}

else{

$depends="5"

}

$backuparray+=$tempobject

}

$dc.Value | Add-Member -MemberType NoteProperty -Name "backupsparsed" -Value $backuparray

}

That is, now we have a new property in our hash table with the parsed backup info. So for example to see if there are DCs that do not have performed bare metal backups we can simply run

$results.values.backupsparsed | where contents -NotLike "*bare*" | select computername -Unique

Piece of cake, a problem solved in 30 minutes that without powershell would have taken ages…

Hope you found it interesting!

Fernando Rubio]]></content:encoded>
    </item>
    <item>
      <title>Documenting an AD based DNS infrastructure using powershell</title>
      <link>https://docs.microsoft.com/archive/blogs/fernandorubio/documenting-and-ad-based-dns-infrastructure-using-powershell</link>
      <pubDate>Fri, 13 Apr 2018 10:54:34 GMT</pubDate>
      <dc:creator><![CDATA[Fernando Rubio Roman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/fernandorubio/?p=105</guid>
      <description><![CDATA[Hi

Following with the work done to document an AD infrastructure using powershell that i...]]></description>
      <content:encoded><![CDATA[Hi

Following with the work done to document an AD infrastructure using powershell that i explained in this post

https://blogs.technet.microsoft.com/fernandorubio/2018/01/26/how-to-document-your-infrastructure-in-an-xml-file-by-using-parallelexecution-powershell-module/

Today we will talk about how to document an AD DNS based infrastructure. If you have your DNS server running on Domain Controllers, most probably you are using AD integrated zones.  They support multimaster updates, automatically appearing in new domain controllers, supports ACLs... definetely the way to go. So if you just exported all the LDAP partitions the info is just there but the dnsrecord info is stored on a dns-node object under the dns-record attribute on a binary format.

<a href="https://msdn.microsoft.com/en-us/library/ms675527(v=vs.85).aspx">https://msdn.microsoft.com/en-us/library/ms675527(v=vs.85).aspx</a>

This is one of these cases in which it makes sense to use the service specific powershell cmdlets to retrieve and store the dns information for future reference. With the help of Adrian Crespo we created the following script to be invoked once per domain. Sorry for the lack of comments

<a href="https://github.com/fernandorubioroman/DocumentAD/blob/master/scripts/documentDNS.ps1">https://github.com/fernandorubioroman/DocumentAD/blob/master/scripts/documentDNS.ps1</a>

$results=@{}
$recordresults=@{}
$policies=@{}
$OSVersion=((Get-CimInstance win32_operatingsystem).Version).split(".",2)[0]
#if on 2016 we need to collect more info as scopes could be used
if ($osversion -gt 6){
$zones=$null
$zones=Get-DnsServerZone
$server=Get-DnsServer -ErrorAction SilentlyContinue
$results.add("dnszones",$zones)
$results.add("dnsserver",$server)
foreach ($zone in $zones){
$records=$null
$scopes=$null
$scopes=get-dnsserverzonescope -zonename $zone.ZoneName
foreach($scope in $scopes){
$records=Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -zonescope $scope.Zonescope
$recordresults.add(($zone.ZoneName+"_"+$scope.ZoneScope),$records)
}
$records=Get-DnsServerResourceRecord -ZoneName $zone.ZoneName
$recordresults.add($zone.ZoneName,$records)
$zonepolicies=$null
$zonepolicies=Get-DnsServerQueryResolutionPolicy -ZoneName $zone.ZoneName
$policies.add($zone.ZoneName,$zonepolicies)
}
$results.add("dnsrecords",$recordresults)
$results.Add("dnspolicies",$policies)
$conditional = Get-DnsServerForwarder
$results.Add("conditional", $conditional)
$globalpolicies=$null
$globalpolicies=Get-DnsServerQueryResolutionPolicy
$results.Add("dnsglobalpolicies",$globalpolicies)
}
#this is for 2008r2, 2012...
else{
$zones=$null
$zones=Get-DnsServerZone
$server=Get-DnsServer -ErrorAction SilentlyContinue
$results.add("dnszones",$zones)
$results.add("dnsserver",$server)
foreach ($zone in $zones){
$records=$null
$records=Get-DnsServerResourceRecord -ZoneName $zone.ZoneName
$recordresults.add($zone.ZoneName,$records)
}
$results.add("dnsrecords",$recordresults)
$conditional = Get-DnsServerForwarder
$results.Add("conditional", $conditional)

}
return $results

&nbsp;

Basically we collect a bunch of info, the zones, and records on each one, forwarders...also for 2016 we collect scopes and records on each one as welll as the defined policies. If you haven´t dig into 2016 scopes take a look at this link

<a href="https://docs.microsoft.com/en-us/windows-server/networking/dns/deploy/dns-policies-overview">https://docs.microsoft.com/en-us/windows-server/networking/dns/deploy/dns-policies-overview</a>

That is! call it from your parallelexecution engine or locally at a server and you will have a backup of how your dns looks for future reference...

Cheers

Fernando

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>How to document your infrastructure in an XML file by using parallelexecution powershell module</title>
      <link>https://docs.microsoft.com/archive/blogs/fernandorubio/how-to-document-your-infrastructure-in-an-xml-file-by-using-parallelexecution-powershell-module</link>
      <pubDate>Fri, 26 Jan 2018 18:23:25 GMT</pubDate>
      <dc:creator><![CDATA[Fernando Rubio Roman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/fernandorubio/?p=55</guid>
      <description><![CDATA[Hello again

Today, I will showcase how we can leverage the parallelexecution powershell module,...]]></description>
      <content:encoded><![CDATA[Hello again

Today, I will showcase how we can leverage the parallelexecution powershell module, to document a whole environment.

We will use advanced features such as the usage of commands files and of parallel script execution. For this example, we will work against an Active Directory environment, but it could be easily modified to document any other kind of infrastructure that supports Powershell such as Exchange, Sharepoint, Lync and many others.

IMPORTANT NOTE: This code is a sample that will probably crash due to an out of memory condition if executed as is against a big enterprise Active Directory, so please use it carefully and understand what you are doing before running against a production AD)

All code I will use for this example is published on github here:

<a href="https://github.com/fernandorubioroman/DocumentAD/">https://github.com/fernandorubioroman/DocumentAD/</a>

The main code we will use is this

<hr />

<em>#requires -modules parallelexecution</em>

<em>#requires -version 3</em>

<em>#First we get an array of Domains, of all DCs in the Forest and of the best ones (in the same site as we are) to collect extensive domain data from them</em>

<em>$domains=(Get-ADForest).domains</em>

<em>$dcs=@()</em>

<em>$bestdcs=@()</em>

<em>$date=get-date -Format yyyyMMddhhmm</em>

<em>foreach ($domain in $domains){</em>

<em>$dcs+=get-addomaincontroller -filter * -server $domain</em>

<em>$bestdcs+=get-addomaincontroller -server $domain</em>

<em>}</em>

<em>#Then we get the information per domain</em>

<em>$bestdcs| select -ExpandProperty hostname| Start-ParallelExecution -InputCommandFile .\commandDomain.csv -OutputFile ".\output_domains_$($date).xml" -TimeoutInSeconds 900 -Verbose</em>

<em>#Then we get the information we want per DC</em>

<em>$dcs| select -ExpandProperty hostname | Start-ParallelExecution -InputCommandFile .\commandDC.csv -OutputFile ".\output_DCs_$($date).xml" -TimeoutInSeconds 900 -ScriptFolder .\scripts -Verbose</em>

<em>#we compress and delete the output files</em>

<em>Get-ChildItem -Path .\ |where{$_.Extension -eq ".xml"} | Compress-Archive -DestinationPath .\DocumentedAD$date.zip</em>

<em>Get-ChildItem -Path .\ |where{$_.Extension -eq ".xml"} | remove-item</em>

<hr />

<em>Le</em>t understand that code line by line

<em>#requires -modules parallelexecution</em>

<em>#requires -version 3</em>

As we said we will use the parallelexecution module, so if you have not yet installed it in your collection machine, go review this article.

<a href="https://blogs.technet.microsoft.com/fernandorubio/2018/01/25/powershell-remoting-made-easy-with-parallelexecution-module/">https://blogs.technet.microsoft.com/fernandorubio/2018/01/25/powershell-remoting-made-easy-with-parallelexecution-module/</a>

We also need version 3 of PowerShell (but really, on the machine you use to launch scripts you should be using PowerShell 5 anyway)

<em>#First we get an array of Domains, of all DCs in the Forest and of the best ones (in the same site as we are) to collect extensive domain data from them</em>

<em>$domains=(Get-ADForest).domains</em>

<em>$dcs=@()</em>

<em>$bestdcs=@()</em>

<em>$date=get-date -Format yyyyMMddhhmm</em>

<em>foreach ($domain in $domains){</em>

<em>$dcs+=get-addomaincontroller -filter * -server $domain</em>

<em>$bestdcs+=get-addomaincontroller -server $domain</em>

<em>}</em>

&nbsp;

We first get the list of domains from the AD forest, then we initialize a couple of other arrays, $dcs will be used to store all Domain Controllers in the forest, $bestdcs will contain one Domain Controller per domain that is near (in the same site) that the machine we are using to collect extensive AD data that is replicated at the Domain level and that therefore we just need to collect once for Domain.

We also get the current date and time, so that output files are timestamped and finally, we iterate over the domains populating the dcs and bestdcs arrays.

<em>#Then we get the information per domain</em>

<em>$bestdcs| select -ExpandProperty hostname| Start-ParallelExecution -InputCommandFile .\commandDomain.csv -OutputFile ".\output_domains_$($date).xml" -TimeoutInSeconds 900 -Verbose</em>

&nbsp;

Now, is when the magic begins. We pipe the list of the preferred DCs per domain (as objects with lots of properties), we extract from there the hostnames as that is all we are interested about (select -ExpandProperty hostname) and then call start-parallelexecution using that list of machines as input. Let´s understand which parameters we are using

<em>-InputCommandFile .\commandDomain.csv</em>

So instead of asking our engine to execute a single command, we use a commands file. This is a # separated file (we didn´t use “,” or “;” as these characters are used from time to time inside powershell commands) In our example commandDomain.csv looks like this

<hr />

propertyname#command#Script#Description

AllADObjects#get-adobject -filter * -properties *#false#Get all data about all AD objects, do not launch this on a huge enterprise

Users#get-aduser -filter * -properties *#false#Get alldata about all users

Machines#get-adcomputer -filter * -properties *#false#Get all data about all machine objects

Groups#get-adgroup -filter * -properties *#false#Get all data about all group objects

GPOs#get-gpo -all#false#get the list of all GPO objects

GPOReport#Get-GPOReport -All -ReportType xml#false#get an xml report representing all existing GPOs

DCInfo#get-addomaincontroller -filter *#false#retrieves the list of dcs in the domain in the domain

FineGrainedPasswordPolicy#Get-ADFineGrainedPasswordPolicy -Filter *#false#gets the fine grained password policies

#ADOptionalFeature#Get-ADOptionalFeature -filter *#false#get the enabled optional features such as recycle bin

OUs#Get-ADOrganizationalUnit -filter * -Properties *#false#get the list of all OUs

RootDSE#Get-ADRootDSE#False#Get the root DSE info

ServiceAccounts#Get-ADServiceAccount -Filter * -Properties *#False#Get all AD service accounts info

Trusts#Get-ADTrust -Filter * -Properties *#False#get all trust information

ADReplicationMetadata#Get-ADReplicationPartnerMetadata -Target $env:computername#False#Get Ad replication metadata

<hr />

&nbsp;

It´s easier to read or modify it if you open it in Excel and use # as separator

<img width="1024" height="294" class="alignnone size-large wp-image-65" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/01/commandsdomain-1024x294.png" />

Much better. Our commands file has 4 columns. <strong>Propertyname</strong> is just a name, that will be used to store the results. (more on this later), <strong>Command</strong> is the actual command or script we want to execute. If command as in this example we just put there the actual code we want executed, if script we put the name of the script. The <strong>script</strong> columns specify if we are running a command (false) or a script (true). And finally, <strong>description</strong> is a text that helps describing the command we are executing.

<em>-OutputFile ".\output_domains_$($date).xml"</em>

The next parameter is the output file we want to extract the collected info to, we could just pipe this to the console, or to a variable but in this case, we want to save the collected info. We include the date on it so that if you end up creating a scheduled task for this, it is easy to take your time machine and see how the environment was at a specific date.

<em>-TimeoutInSeconds 900</em>

This parameter specifies for how long we are going to wait for each command to finish before failing.

<em>-Verbose</em>

This parameter specifies if we want verbose output, so instead of running silently you get an output such as this:

<img width="1024" height="180" class="alignnone size-large wp-image-75" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/01/verbose-1024x180.png" />

Going back to our code…

#Then we get the information we want per DC

<em>$dcs| select -ExpandProperty hostname | Start-ParallelExecution -InputCommandFile .\commandDC.csv -OutputFile ".\output_DCs_$($date).xml" -TimeoutInSeconds 900 -ScriptFolder .\scripts -Verbose</em>

Very similar to the previous one, the only differences is that we run this against all DCs in the forest, that we use a different commands file, commandsDC.csv and that we are specifying a scripts folder

The commandsDC.csv used looks like this

<hr />

propertyname#command#Script#Description

Fixes#get-hotfix | Select-Object PSComputerName,InstalledOn,HotFixID,InstallDate,Description#False#Get the list of installed hotfixes #

Services#get-service#False#Get the services information

ScheduledTasks#get-scheduledtask#False#Get the scheduled tasks

RegAssociationsMachine#get-childitem -path "HKLM:\Software\Classes"#False#gets the machine file associations

Drivers#get-windowsdriver -online#False#Get the list of third party drivers running on the machine

Audit#auditpol.ps1#true#get the audit policy of the machine using auditpol

OSInfo#get-wmiobject Win32_OperatingSystem#False#Get the OS information and version#

ComputerInfo#get-wmiobject Win32_ComputerSystem#False#Get the machine name, manufacturer, model, etc#

DiskInfo#Get-wmiobject Win32_logicaldisk |where-object{$_.drivetype -eq 3}#False#Get the disk information

##############Network Config##############

IPInfo#get-wmiobject Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE #False#Get the ip network card information#

Shares#get-wmiobject Win32_share#False#Get the list of shares

netstat#get-NetTCPConnection#False#Get the opened network connections

routeprint#get-netroute#false#gets the machine routes

HostParsed#hostparsed.ps1#true#Gets the parsed contents of the host file

##############Certificates##############

RegCertificatesmachine#get-childitem -path "HKLM:\Software\Policies\Microsoft\SystemCertificates" -recurse#False#get the machine info about certificates from registry

CertificatesAuthroot#get-childitem -path cert:\LocalMachine\Authroot#False#get the certificates in the authroot container

certificatesroot#get-childitem -path cert:\LocalMachine\root#False#get the certificates in the root container

##############Miscelaneous##############

EnvironmentVariables#Get-ChildItem Env:#False#Get the environment Variables

ADReplicationConnection#Get-ADReplicationConnection -Server $env:COMPUTERNAME#false#get the replication connections

<hr />

A couple of important things about the commands file.

First notice that lines starting with # are ignored so you can use that to split the files in parts or to disable specific checks.

Then look at this line

<em>Audit#auditpol.ps1#true#get the audit policy of the machine using auditpol</em>

Here is an example of a script being called, instead of the command we specify the name of the script (the path is specified in the scriptsfolder parameter) and the third column is set to true because this is an script. (The actual code of the auditpol script that I use to parse the audit policy is on the github I referenced at the beginning of this article)

&nbsp;

<em>#we compress and delete the output files</em>

<em>Get-ChildItem -Path .\ |where{$_.Extension -eq ".xml"} | Compress-Archive -DestinationPath .\DocumentedAD$date.zip</em>

<em>Get-ChildItem -Path .\ |where{$_.Extension -eq ".xml"} | remove-item</em>

These last lines retrieve the generated xml files, compress them for future reference and then deletes the original files.

Well, that is, piece of cake, right? The question is what we can do with the collected info. To load the output to a variable we can run:

<em>$domainsdata=Import-Clixml -Path .\output_domains_201801261041.xml</em>

<em>$DCdata=Import-Clixml -Path .\output_DCs_201801261041.xml</em>

Then, we can access the collected information such as in the picture

<img width="1024" height="388" class="alignnone size-large wp-image-85" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/01/datadc-1024x388.png" />

The collected data, is a hashtable, for a more detailed explanation about hashtables check:

<a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-5.1">https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-5.1</a>

in simple terms, a hashtable is a indexed collection of keys and values. In our case, the keys are the name of the machines we have been working with,and the values are powershell objects, that will have one property per each one of the commands we executed against them (named using the propertyname, first column of the csv file). The content of each property will be the result of the command we executed against that machine.

For example running

<em>$DCdata.'rootdc1.contoso.com'.fixes | select HotfixID,Installedon | ft *</em>

<img width="1024" height="470" class="alignnone size-large wp-image-95" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/01/fixes-1024x470.png" />

That’s all for today, hope you have found it interesting. I will keep updating the csv files that document the AD infrastructure, if you have any suggestion please let me know!

Cheers

Fernando]]></content:encoded>
    </item>
    <item>
      <title>Bulk powershell remoting made easy with parallelexecution module</title>
      <link>https://docs.microsoft.com/archive/blogs/fernandorubio/powershell-remoting-made-easy-with-parallelexecution-module</link>
      <pubDate>Thu, 25 Jan 2018 10:20:05 GMT</pubDate>
      <dc:creator><![CDATA[Fernando Rubio Roman]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/fernandorubio/?p=25</guid>
      <description><![CDATA[Write-host "hello world"

During the last months, with the help of Alvaro Jimenez &amp; Raul...]]></description>
      <content:encoded><![CDATA[Write-host "hello world"

During the last months, with the help of Alvaro Jimenez &amp; Raul Carboneras i have been working on a new powershell module to simplify the administration of multiple Windows systems using Powershell. (For v2 we will look into incorporating Linux systems using PS core)

The idea is quite simple but powerfull. Let explain it with an example.

<img width="1024" height="190" class="alignnone size-large wp-image-45" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/01/Capture12-1024x190.png" />

We start by running:

$results=Get-ADDomainController -filter * | select -ExpandProperty hostname | Start-ParallelExecution -Command "get-service" -Verbose

The previous command get the list of all domain controllers in a domain (as objects), get from it the hostnames, and finally use that as input for the start-parallelexecution command, the core of this module, that in this case runs a single command, get-service to retrieve the list of services on each machine. All that runs as Powershell jobs through remoting sessions in parallel so can handle hundreds of machines in a matter of seconds.

The results are stored in $results, if we investigate $results we will see is a hashtable with one entry per machine, each entry containing an object that stores the result of the execution of the command as one property. That means we can do things like...

$results.'rootdc1.contoso.com'.results | where{$_.name -eq "ADWS"}

To see if the ADWS service is running on rootdc1

Or even better

$results.values.results | where{$_.name -eq "ADWS"}

To see in which machines that service exists.

Go ahead and give it a try. It supports using multiple credentials for different domains, copying prerequisites to destination machines (for example to copy custom modules that are later on referenced), using scripts instead of commands for more complicated tasks, specifying multiple command using a csv file (what about documenting an infrastructure on a single command...), redirecting to an xml file for future reference, and much more...

The code is now on the powershell gallery so you can install it on any Powershell 5 system with Internet running "install-module parallelexecution" you can also download it from here

<a href="https://www.powershellgallery.com/packages/parallelexecution/">https://www.powershellgallery.com/packages/parallelexecution/</a>

The source code is available on github

<a href="https://github.com/fernandorubioroman/parallelexecution/">https://github.com/fernandorubioroman/parallelexecution/</a>

&nbsp;

Hope you find it useful!

Fernando]]></content:encoded>
    </item>
  </channel>
</rss>