A note on the scripts in this blog

Featured

When this Blog was migrated from Windows Live to WordPress some things did not translate well or at all. The most noticeable are “\”; that’s the “\” as in c:\ or in C:\Scripts\PS1. which just isn’t there anymore. They also put “the and sign” nbsp; in the place of spaces and tabs and `< and `> with the “and sign” gt and the “and sign” lt.

I don’t know why or how, but if you copy these scripts, you will need to check these very closely.

Thank you for your support.

Parsing error messages

I wanted to reduce the amount of verbiage in an error message. I came up with this.


$ScriptName = $MyInvocation.MyCommand.Name # gets name of the script that is running
$Error.clear()
# Introduce an error for testing
Stop-Process -Name invalidprocess -EA "SilentlyContinue"
If ($Error) {
$E1 = $E2 = $E3 = $E4 = $E5 = " " #Sets variables to null.
$E1 = [string]$Error.Exception #Catches error
$E2 = $E1.Split(":") # divides the string at the :
$E3 = $E2[1] # Selects the part of the string after the :
$E4 = $E3.Split("\.") # divides the result at the period
$E5 = $E4[0] # selects the first part of of the string
# Write-Log -Message "$ScriptName $E5" -Path $LogPath warn # writes the result to the log
# Break # exits the script
}
Write-Host $E5

For some reason the above script has stopped working. It appears that something has changed in PS ver 2 on Windows 7 at least.
If the above does not work try this:

 


Function err {
If ($Error) {
$E1 = $E2 = $E3 = $E4 = " " #Sets variables to null.
[string]$E1 = $Error #Catches error
[string]$E2 = $E1.split(":") # divides the string at the ":"
$E3 = $E2.split(".") # divides the string at the "."
$E4 = $E3[0] # Selects the part of the string before the "."
Write-Host $E4
}
$Error.clear()
}

 

trouble re-installing Microsoft CRM 2013 ( “IIS URL Rewrite Module”)

I am working in an environment with several servers running MSCrm 2013. Three of these servers had there D and E drives wiped in error. Unfortunately, CRM was installed on the D: dive. When I tried to re-install CRM I kept getting an error about the UrlRewriteModule. I tried repairing it and I even reinstalled it, but that did not help. Finely, I uninstalled it and then installed CRM. That time it worked. It seems that CRM wants to install the UrlRewriteModule itself. So, if you are having similar problems with any of the Prerequisites, I would recommend going to the control panel and uninstalling them and letting CRM re-install them. I have found that if I get a 500.19 error when I first try to connect to the CRM web page that repairing the UrlRewriteModule fixes that problem.

Audit Folders/Shares and Export to CSV file

# NAME: AuditPerms2CSV.ps1
#
# AUTHOR: OldDog
# DATE : 11/12/2014
#
# COMMENT: Audit Folders/Shares and Export to CSV file
# This saves the results in a directory called C:\powershell\results
# if you don't have that directory it will create one.
# It also deletes any existing copy of Result.csv so if you want to save them rename them.
# ==============================================================================================
$path = $args[0]

if (! $args ) {
$path = Read-Host “Please enter the full path name you wish to check, like this: \\FileServer\share\user”

}

If (Test-path “C:\Powershell\Results”) {
If (Test-path “C:\Powershell\Results\Result.csv”) {
del “C:\Powershell\Results\Result.csv” }
}
Else {
New-Item -Path “C:\Powershell\Results” -ItemType directory
}

Add-Content “C:\Powershell\Results\Result.csv” “Folder Path:, Users/Groups:,Permissions:,Permissions Inherited:”

####Change the path to the folder or share you want NTFS perms on####
$dirToAudit = Get-ChildItem -Path $path -recurse | Where {$_.psIsContainer -eq $true}

foreach ($dir in $dirToAudit)
{
$colACL = Get-Acl -Path $dir.FullName

foreach ($acl in $colACL)
{
If ($acl.Access | ? inheritanceflags -eq ‘none’){
$In = $false } Else {$In = $True }

foreach ($accessRight in $acl.Access)
{
$DirName = $dir.FullName
$ar = $($AccessRight.FileSystemRights)
$id = $($AccessRight.IdentityReference)
Add-Content “C:\Powershell\Results\Result.csv” “$dirName ,$id,””$ar””,$In” #Note the “” to escape the ‘,’ in the permissions
}
$In = $null
}

}

Using PowerCLI to find all the VM’s with ISO’s attached


#Create an instance of the Excel.Application
$xl = New-Object -comobject excel.application
$xl.Visible = $true
$xl.DisplayAlerts = $False
$wb = $xl.Workbooks.Add()
$ws = $wb.Worksheets.Item(1)
$ws1 = $wb.worksheets | where {$_.name -eq "Sheet1"} #<------- Selects sheet 1

$ws1.Cells.Item(1,1) = “VM”
$ws1.Cells.Item(1,2) = “CD Drive ISOPath”
$row = 2

$vms = get-vm | select Name | sort
foreach ($i in $vms) {
$Item = [string]$i
$g = $Item.Split(“=”)
$Name = $g[1].Trimend(“}”)
$CDConnected = Get-CDDrive $Name | where { ($_.ConnectionState.Connected -eq “true”) -and ($_.ISOPath -like “*.ISO*”)}
If ($CDConnected -ne $null) {
$ws1.Cells.Item($row,1) = $Name
$ws1.Cells.Item($row,2) = $CDConnected.IsoPath
$row++
[void]$ws1.cells.entireColumn.Autofit()
}
}

[\sourcecode]

My New Thing: Desired State Configuration

I have been working on a contract for about four months now. Originaly I was tasked with provisioning about 500 servers at a new data center using vmWare. I started doing them one at a time using the vmWare front end. I soon was persauded to investigate powerCli and I was able to script the installs. That is much better and faster. In the mean time, a couple of other guys were working on this thing called DSC or Desired State Configuration. This is a Powershell V4 script that automates your server configuration and if done correctly, keeps the configuration intact. If you want to know about this in more detail check out the *”FREE”* “DSC BOOK” at http://powershell.org/wp/ebooks/ once there Access all of their free eBooks in their Public OneDrive Folder.

Both of those guys left and I was tasked with finishing the project.

I have had many adventures getting this stuff to work an I plan on detailing some of them in future posts.

Get SharePoint Site Owner and/or Site Admin

One of the things you might have to do as an admin in a large organization is to find out if a particular user is a SharePoint Site Owner and Admin. I had to do this when a long time SharePoint developer left the company.

They are not the same thing, no matter what you may read.
You can find a discusion on the difference here:

http://techtrainingnotes.blogspot.com/2008/03/sharepoint-site-administrator-vs-site.html

This script will sort through all the owners and members of the site admin group on a given server. It will locate your user if they are an Owner or an admin on any SharePoint site on that server.

It uses the SharePoint snapin and at least where I work, I need to run it as the Farm Administrator.
The output is a tab delimited file that opens up nicely in Excel.

 


Function SiteAdmin($site){
$siteUrl = $site.url
$rootSite = New-Object Microsoft.SharePoint.SPSite($siteUrl)
$spWebApp = $rootSite.WebApplication

foreach($site in $spWebApp.Sites)
{
    foreach($siteAdmin in $site.RootWeb.SiteAdministrators | where {$_.LoginName -Like $user})
		{
	  Add-Content -Path $strPath "`t`t$($siteAdmin.ParentWeb.Url) `t $($siteAdmin.DisplayName) `t $($siteAdmin.LoginName)"
		}
	}
}

Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$user = Read-Host "Input user name or part thereof to find [Contoso\User*]"
$date = Get-Date
$comp = $env:computername
$strPath = $filename = "E:\Reports\users.txt"
IF(Test-Path $filename) { Remove-Item $strPath }
Add-Content -Path $strPath "$User Owner and\or Admin `t$comp `t$date`n"
Add-Content -Path $strPath "Site.Url `tSite Owner `tParentWeb Url `tSiteAdmin DisplayName `tSiteAdmin LoginName"

$Sites = Get-SPSite -Limit All
ForEach ($site in $Sites) {
	SiteAdmin($site)
	If ($site.owner -Like $user) {
	Add-Content -Path $strPath "$($Site.Url) `t $($Site.Owner)"
	}
	$site.Dispose()
}

 

My SharePoint 2010 Powershell tutorial for SharePoint 200 developers

Serge Luca aka "Doctor Flow" (Microsoft Power Platform/Business Applications MVP)

Here is an extract of the Powershell module of my  SharePoint 2010 for developers course.

 

1.1 lab.introduction to Powershell

In this lab, you will work out a number of exercises that have to do with Powershell.

In Lab1 you will discover the main Powershell concepts; in Lab 2, you will apply these concepts.

1.1.1 Lab 1.discovering Powershell

1. Start the Sharepoint 2010 Management Shell.

clip_image002

2. To get help, type:

Get-help

3. To see all the commands available, type :

4. To see how to use Get-Command, type get-help get-Command; you will notice the Noun option:

clip_image003

5. To get the list of all Sharepoint commands, type:

You will notice familiar cmdlets like Get-SPUser, Get- SPWeb, Get- SPSite,…

Sharepoint commands are organized as verb-noun like Enable-SPFeature.

You can type Get-Command –Noun SPFeature*or Get-Command –verb Enable.

6. In Powershell, there…

View original post 1,291 more words

Get SharePoint Users and Groups Info

This script uses the SharePoint commands to gather all the users and groups with access to your Central Administration SP site.
It mails the report using SMTP and it will upload the report to a SharePoint site.
This script must be run as a Farm Administrator to get complete results.

It puts it out in a HTML format. It is usefull for those security audits that come up from time to time.
The is adapted from the code I found here which puts out the results in a quasi XML format.
:

#Function to send out email 
function sendMail($emailTo,$outFile) 
{ 
    $smtpServer = "smtp.org" #<-- Your SMTP mail server
    $emailFrom = "$machineName@yourdomain.com"  
    $subject = "$MachineName SharePoint Users Info - $date" 
    $body = "See Attached."  
	
	If ($outFile -eq $null) {
		# no attachement
		$body += $Results
        Send-MailMessage -From $emailFrom -To $emailTo -Subject $subject  -Body $body -SmtpServer $smtpServer 
	}
	Else
	{
		# with $outfile as attachement
        Send-MailMessage -From $emailFrom -To $emailTo -Subject $subject  -Body $body -Attachments $outFile -SmtpServer $smtpServer
    }
} 

function DisplayWeb #-web SPWeb -depth int -parentWeb SPWeb
{
   if($args[0].HasUniquePerm -eq "True")
  {
    $UserAccess = DetermineUserAccess $args[0] ($args[1] + 1)
  }
  

  if($args[0].Webs -ne $Null)
  {
    # RECURSIVELY SEARCH SUBWEBS
    foreach ($spSubWeb in $args[0].Webs)
    {
      $subWeb = DisplayWeb $spSubWeb ($args[1] + 2)
      $spSubWeb.Dispose()
    }
    # END CONTAINED SUBSITES ENTITY
   
  }

  # END SITE ENTITY
  Return $subWeb
}

function DisplayMissingParametersMessage
{
  #Write-Output "You are missing a parameter for 'Site URL'"
  $script:siteURL = Read-Host "Enter Site URL"
}
<#
This report must be run as a Farm Administrator to get complete results.
The report will mail itself to a person or group and upload the report file to a 
SharePoint site. ("http://sharepoint/Shared%20Documents")
:: Usage:
.\SP Security Report.ps1' "http://ServerName:51234" <-- Change the server name as appropriate.


#>
############
# MAIN
############

Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

#IF MISSING PARM FOR SITE URL, ASK FOR INPUT TO FILL
if($args.length -eq 0)
{
  DisplayMissingParametersMessage
}

[string]$siteUrl = $args[0]
[string]$searchScope = $args[1]
[string]$userToFind = $args[2]

#Import-module active*
$server = $env:computername
$date = ( get-date ).ToString('MM-dd-yyyy')
$MachineName = $env:COMPUTERNAME
$u = @()
$rootSite = New-Object Microsoft.SharePoint.SPSite($siteUrl)
$spWebApp = $rootSite.WebApplication

#IF SEARCH SCOPE SPECIFIED FOR SITE, ONLY SEARCH SITE
if($searchScope -eq "-site")
{
  DisplaySiteCollection $rootSite 1
}
#ELSE SEARCH ENTIRE WEB APP
else
{
  #DisplayWebApplication $spWebApp 1
}

# Create Webpage Header
$z = "<!DOCTYPE html PUBLIC `"-//W3C//DTD XHTML 1.0 Strict//EN`"  `"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd`">"
$z = $z + "<html xmlns=`"http://www.w3.org/1999/xhtml`">"
$z = "<head><style>"
$z = $z + "TABLE{border-width: 2px;border-style: solid;border-color: black;border-collapse: collapse;}"
$z = $z + "TH{border-width: 2px;padding: 4px;border-style: solid;border-color: black;background-color:lightblue;text-align:left;font-size:14px}"
$z = $z + "TD{border-width: 1px;padding: 4px;border-style: solid;border-color: black;font-size:12px}"
$z = $z + "</style></head><body>"
$z = $z + "<H4>SharePoint Users Report for $env:COMPUTERNAME Central Admin $date</H4>"
$z = $z + "<table><colgroup><col/><col/><col/><col/><col/><col/><col/></colgroup>"
$z = $z + "<tr><th>Web App</th><th>Web</th><th>Site Collection</th><th>Site User</th><th>SPGroup</th><th>SPGroupMembers</th><th>Local Group</th></tr>"
$MainWebApp = $spWebApp
$MainDisplayWeb = DisplayWeb 
$subSite = @()

ForEach ($site in $SpWebApp){
$MainSiteCollection = @()
$a = $site.Sites 
	forEach ($a1 in $a) {
	$sSite = $a1.ToString().split("=")
		$SubSite = $subSite + $sSite[1]
	$MainSiteCollection = "$MainSiteCollection $sSite <br>"
	}
}

$z = $z + "<tr><td>$MainWebApp</td><td>$MainDisplayWeb</td><td>$MainSiteCollection</td><td></td></tr>"

ForEach ($site in $SubSite){
$siteUser = @()
$u1 = @()
$SPGroups = @()
$MainSPGroupMembers = @()
$rSite = New-Object Microsoft.SharePoint.SPSite($site)
$x = $rSite.rootweb
$x1 = $x.users

ForEach ($i in $x1) { 
$u = $i.UserLogin
$u2 = $u.ToString().split(".")
$u1 = "$u1  $u2 <br>"
$siteUser = "$u1<br>"
 }
foreach($group in $rsite.RootWeb.SiteGroups)
{	
    $b = $group.Name 
    $sGroup = $b.ToString().split(".")
	$SPGroup = $sGroup[0]
	$SPGroups = ($SPGroup)
	$LocalGrp = @()
	$lgn = @()
	$lgm = @()
	$MemberName = @()
	$x1 = @()
	$x = $null
	foreach ($user in $group.Users)
    {    
		$D = $user.UserLogin
			$D1 = $D.ToString().split(".")
			$D2 = $D.ToString().split("\")
			$SPGroupMembers = "$D1"
			$MainSPGroupMembers = ("$MainSPGroupMembers $SPGroupMembers <br>")
		If ($User.IsDomainGroup) {
			$x = $user
			$lgn = $x
			$x1 = $x1 + $x 
			forEach ($x2 in $x1) {
			$Lgm = $Null
			$y = $Null
			$gName = $x2.ToString().split("\")
			$groupName = $gName[1]
			  #BEGIN - CODE ADAPTED FROM SCRIPT CENTER SAMPLE CODE REPOSITORY
			  #http://www.microsoft.com/technet/scriptcenter/scripts/powershell/search/users/srch106.mspx
			  #GET AD GROUP FROM DIRECTORY SERVICES SEARCH
			  $strFilter = "(&(objectCategory=Group)(name="+($groupName)+"))"
			  $objDomain = New-Object System.DirectoryServices.DirectoryEntry
			  $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
			  $objSearcher.SearchRoot = $objDomain
			  $objSearcher.Filter = $strFilter
				$colProplist = ("name","member")
				foreach ($i in $colPropList)
					{
					$catcher = $objSearcher.PropertiesToLoad.Add($i)
					}
						$colResults = $objSearcher.FindAll()

				#END - CODE ADAPTED FROM SCRIPT CENTER SAMPLE CODE REPOSITORY
				  foreach ($objResult in $colResults)
				  {
					foreach ($member in $objResult.Properties.member)
					{
					  $indMember = [adsi] "LDAP://$member"
					    $y = $domain + ($indMember.Name) 
						$Lgm = ("$Lgm <tr><td>$y</td></tr>")
						}
					 }
			}	
			$LocalGrp = ("$LocalGrp <TABLE><td><strong>$lgn</strong></td><td>$Lgm</td></tr></TABLE>")
			}
	}
	$lgnlgm = $Localgrp
	$z = $z + "<tr><td></td><td>$site</td><td></td><td>$siteUser</td><td>$SPGroups</td><td>$MainSPGroupMembers</td><td>$lgnlgm</td><tr>"
	}
	$rSite.Dispose()
}

# Create Table
$surl = $siteUrl.ToString().split("/")
$s = "CA"
# $s = $surl[2]
# $s = ($s -replace ":", "-") 
$MainWebApp = $spWebApp
$MainDisplayWeb = DisplayWeb
$z = $z + "</table></body></html>"

# Adjust Path
$OutFileName = ("G:\Reports\" + $server + "-" + $s + "-SharePoint Security Report-" + $date + ".html")
#
Out-File -FilePath $OutFileName -InputObject $z -Encoding ASCII	
#End Table
$OutFileItem = Get-Item -Path $OutFileName
Write-Host " Report available here: $OutFileItem" -Foregroundcolor Yellow
sendMail user@yourmai.com $OutFileItem #<--- Change email address

# upload the report to a SharePoint site
$userName = Read-Host "Enter your username"
$password = Read-Host "Enter your password"
 
 $path = "G:\Reports"; #<--- Change directory
 $destination = "http://sharepoint/Shared Documents"; 
 $securePasssword = ConvertTo-SecureString $password -AsPlainText -Force;
 $credentials = New-Object System.Management.Automation.PSCredential ($userName, $securePasssword);
 #$credentials = [System.Net.CredentialCache]::DefaultCredentials; 
 $webclient = New-Object System.Net.WebClient;
 $webclient.Credentials = $credentials; 
 Get-ChildItem $path | Where-Object {$_.Extension -eq ".html"} | 
 ForEach-Object { $webclient.UploadFile($destination + "/" + $_.Name, "PUT", $_.FullName); 
 }
#CLEANUP
$rootSite.Dispose()

Get the SSL Certs by Web Site

I need to check several Web servers for sites that might have an expiring certification.
This pulls the information and adds it to an Excel Spreadsheet.
Note that this only works on 2008 servers.

$date = Get-Date
$rDate = (Get-Date -format "MM-dd-yyyy")
$strPath = "C:\Scripts\PS1\serverinfo-$rDate.xlsx" 
$xl = New-Object -comobject Excel.Application 
$xl.Visible = $True
$xl.DisplayAlerts = $False

$wb = $a.Workbooks.Add() 
$ws = $b.Worksheets.Item(1) 
$ws.Name = $rDate
$ws.Cells.Item(1,1) = "Machine Name" 
$ws.Cells.Item(1,2) = "FriendlyName" 
$ws.Cells.Item(1,3) = "NotAfter" 
$ws.Cells.Item(1,4) = "Issuer" 

$xRow = 2
$cert = dir IIS:\SslBindings | ? {$_.Port -eq 443} | Select *
foreach ($i in $cert) { 
$x = $i.thumbprint
$y = get-item cert:\LocalMachine\My\$x
$FN = $y.FriendlyName
$NA = $y.NotAfter
$IS = $y.Issuer
$ws.Cells.Item($xRow,1) =$comp 
$ws.Cells.Item($xRow,2) =$FN 
$ws.Cells.Item($xRow,3) =$NA 
$ws.Cells.Item($xRow,4) =$IS 
$xRow++
}

This version pulls the info and puts it into a Tab delimited file. I had to run this on each individule server
due to some restriction in my enviroment.

$comp = $env:computername
$strPath = "C:\Scripts\PS1\Certificates\$comp-CertInfo.csv"  # <-- You might want to point this at a share
$date = Get-Date
$rDate = (Get-Date -format "MM-dd-yyyy")
IF(Test-Path $strPath) { Remove-Item $strPath }
Add-Content -Path $strPath "Certificate Inventory `t$rDate`n"
Add-Content -Path $strPath "Machine Name`tFriendlyName `tNotAfter `tIssuer"

$OS = Get-WmiObject Win32_OperatingSystem
$osVer = $os.version
If ($osVer -like "6*") {
$cert = dir IIS:\SslBindings | ? {$_.Port -eq 443} | Select *
foreach ($i in $cert) { 
$x = $i.thumbprint
$y = get-item cert:\LocalMachine\My\$x
$FN = $y.FriendlyName
$NA = $y.NotAfter
$IS = $y.Issuer
Add-Content -Path $strPath "$comp `t$FN `t$NA `t$IS `n";
	}
}
Notepad $strPath

Automates a SharePoint 2010 installation

###### Start Posh Script ######## 

<#
.Script Name
New-SPInstallation.ps1 

.SYNOPSIS
Automates a SharePoint 2010 installation.

.DESCRIPTION
The script automates a SharePoint 2010 installation.
Requires that the binaries are installed on the server.

.PARAMETER databaseName
Name of the configuration database.

.PARAMETER databaseServer
Name of the database server.

.PARAMETER centralAdminDatabase
Name of the Central Administration content database.

.PARAMETER port
Port to use.

.PARAMETER windowsAuthProvider
NTLM or Kerberos, default set to NTLM.

.PARAMETER userName
Farm Administrator account in the format ‘domain\username’.

.PARAMETER password
Pasword for the Farm Administrator account.

.PARAMETER passPhrase
Farm password, used to add new machines to the farm.
#>

param(
[string]$databaseName,
[string]$databaseServer,
[string]$centralAdminDatabase,
[string]$port,
[string]$windowsAuthProvider = "NTLM",
[string]$userName,
[string]$password,
[string]$passPhrase
)
Add-PSSnapin Microsoft.SharePoint.Powershell
$Host.Runspace.ThreadOptions = "ReuseThread"

# Converting password strings to secure strings
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$securePassPhrase = ConvertTo-SecureString -String $passPhrase -AsPlainText -Force

# Creating a PSCredential object
$psCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $userName, $securePassword

# New Configuration Database
New-SPConfigurationDatabase -DatabaseName $databaseName -DatabaseServer $databaseServer -AdministrationContentDatabaseName $centralAdminDatabase -Passphrase $securePassPhrase -FarmCredentials $psCredentials

# Install help files
Install-SPHelpCollection -All

# Install services
Install-SPService

# Install Features
Install-SPFeature -AllExistingFeatures

# Create a new Central Administration
New-SPCentralAdministration -Port $port -WindowsAuthProvider $windowsAuthProvider

# Copy shared application data
Install-SPApplicationContent

###### End Posh Script ######## 

We can run this script by typing the following:

New-SPInstallation.ps1 -databaseName “My config DB” `
-databaseServer “SqlServer01” `
-centralAdminDatabase “My Admin_ContentDB” -port 5057 `
-username “ps\admin” `
-password “SecretP@assword” -passphrase “JoinDoain”