• PowerShell script to set the State of a record in Microsoft CRM 2011 (SOAP)

    I wanted to mark a meeting/appointment as completed via code. I came up with the PowerShell script below. Maybe it will be of use to some one?

    
    FUNCTION JBM-CRM-SetState {
    PARAM(
        [string][ValidateSet("crmserver.company.com", "dev-crmserver.company.com")]$ServerName="crm.sardverb.com",
        [string][ValidateSet("CRMOrganizationName")]$OrganizationName="SardVerbinnen",
        [string][parameter(Mandatory=$true)][ValidateSet("email", "phonecall", "appointment")]$EntityType,
        [string][parameter(Mandatory=$true)][ValidateScript({ $_ -match("^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$")})]$TargetGUID,
        $State=1,$Status=3,[switch]$MyDebug
        )
    $requestMain = ""
    $requestMain += "<s:Envelope xmlns:s=`"http://schemas.xmlsoap.org/soap/envelope/`">";
    $requestMain += "  <s:Body>";
    $requestMain += "    <Execute xmlns=`"http://schemas.microsoft.com/xrm/2011/Contracts/Services`" xmlns:i=`"http://www.w3.org/2001/XMLSchema-instance`">";
    $requestMain += "      <request i:type=`"b:SetStateRequest`" xmlns:a=`"http://schemas.microsoft.com/xrm/2011/Contracts`" xmlns:b=`"http://schemas.microsoft.com/crm/2011/Contracts`">";
    $requestMain += "        <a:Parameters xmlns:c=`"http://schemas.datacontract.org/2004/07/System.Collections.Generic`">";
    $requestMain += "          <a:KeyValuePairOfstringanyType>";
    $requestMain += "            <c:key>EntityMoniker</c:key>";
    $requestMain += "            <c:value i:type=`"a:EntityReference`">";
    $requestMain += "              <a:Id>$TargetGUID</a:Id>";
    $requestMain += "              <a:LogicalName>$EntityType</a:LogicalName>";
    $requestMain += "              <a:Name i:nil=`"true`" />";
    $requestMain += "            </c:value>";
    $requestMain += "          </a:KeyValuePairOfstringanyType>";
    $requestMain += "          <a:KeyValuePairOfstringanyType>";
    $requestMain += "            <c:key>State</c:key>";
    $requestMain += "            <c:value i:type=`"a:OptionSetValue`">";
    $requestMain += "              <a:Value>$State</a:Value>";
    $requestMain += "            </c:value>";
    $requestMain += "          </a:KeyValuePairOfstringanyType>";
    $requestMain += "          <a:KeyValuePairOfstringanyType>";
    $requestMain += "            <c:key>Status</c:key>";
    $requestMain += "            <c:value i:type=`"a:OptionSetValue`">";
    $requestMain += "              <a:Value>$Status</a:Value>";
    $requestMain += "            </c:value>";
    $requestMain += "          </a:KeyValuePairOfstringanyType>";
    $requestMain += "        </a:Parameters>";
    $requestMain += "        <a:RequestId i:nil=`"true`" />";
    $requestMain += "        <a:RequestName>SetState</a:RequestName>";
    $requestMain += "      </request>";
    $requestMain += "    </Execute>";
    $requestMain += "  </s:Body>";
    $requestMain += "</s:Envelope>";
    if ($MyDebug){write-host $requestMain}
    
    $url="http://$ServerName/$OrganizationName/XRMServices/2011/Organization.svc/web"
    
    $http_request = New-Object -ComObject Msxml2.XMLHTTP
    $http_request.Open('POST', $url, $false)
    $http_request.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    $http_request.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    $http_request.setRequestHeader("Content-Length", $xml.length);
    $http_request.send($requestMain);
    if ($MyDebug){$http_request.responseText}
    }
    
    

  • BASH, cURL script to retrieve Google Analytics data

    Last week I wrote this PowerShell code to retrieve Google Analytics data. Below is similar code in BASH using the cURL command.

    #!/bin/bash
    stty -echo
    read -p "Password: " password; echo
    stty echo
    RESULT=$(curl -s https://www.google.com/accounts/ClientLogin \
    --data-urlencode [email protected] --data-urlencode Passwd=$password \
    -d accountType=GOOGLE \
    -d source=YourSource \
    -d service=analytics)
    
    
    AUTH=$(echo "$RESULT" | grep 'Auth=' | sed  s/Auth=//)
    
    curl -s "https://www.google.com/analytics/feeds/data?ids=ga%3AXXXXXXXX&metrics=ga%3Avisits&start-date=2012-05-01&end-date=2012-05-31&max-results=50" \
    --request GET --header "Authorization: GoogleLogin auth=$AUTH"
    
    #Done
    

  • Use PowerShell to get Google Analytics data

    I wanted to write a powershell script that will retrieve the number of visits for my site. I put the following script together. Note this uses Google’s ClientLogin for authentication, which is deprecated. I have not worked with OAuth 2 yet.

    
    function JBM-GA-GetStats {
    PARAM([string][ValidateSet("CurrentMonth","LastMonth","Today","Yesterday")]$Range="CurrentMonth",
            $GAId="XXXXXXXX",$email="[email protected]",[switch]$MyDebug)
    
    [datetime]$Today=[datetime]::Today
    [datetime]$Yesterday=[datetime]::Today.AddDays(-1)
    [datetime]$FirstDayCurrentMonth=$Today.AddDays(- ($Today.Day - 1))
    [datetime]$FirstDayPreviousMonth=$FirstDayCurrentMonth.AddMonths(-1)
    [datetime]$LastDayPreviousMonth=$FirstDayCurrentMonth.AddDays(-1)
    
    switch ($Range){
        "CurrentMonth" {
            $startdate=$FirstDayCurrentMonth.ToString("yyyy-MM-dd")
            $enddate=$Today.ToString("yyyy-MM-dd")
        }
        "LastMonth" {
            $startdate=$FirstDayPreviousMonth.ToString("yyyy-MM-dd")
            $enddate=$LastDayPreviousMonth.ToString("yyyy-MM-dd")        
        }
        "Today" {
            $startdate=$Today.ToString("yyyy-MM-dd")
            $enddate=$Today.ToString("yyyy-MM-dd")   
        }
        "Yesterday"{
            $startdate=$Yesterday.ToString("yyyy-MM-dd")
            $enddate=$Yesterday.ToString("yyyy-MM-dd")   
        }
    }
    
    $pw = read-host "Please Enter Your Password" -AsSecureString
    
    $null = [Reflection.Assembly]::LoadWithPartialName("System.Web")   
    $password= "Passwd=$([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pw)))"
    
    #getting my auth token
    $url="https://www.google.com/accounts/ClientLogin?Email=$($email)&$($password)&accountType=GOOGLE&source=mysource&service=analytics"
    if ($MyDebug){write-host $url}
    $webclient = new-object System.Net.WebClient
    $dataString=$webclient.DownloadString($url)
    $Auth=$dataString.split("`n")[2].split("=")[1]
    if ($MyDebug){write-host $Auth}
    
    #Connecting using auth token to get my data
    $webclient.Headers.Add("Authorization", "GoogleLogin auth=$($Auth)")
    $url="https://www.google.com/analytics/feeds/data?ids=ga%3A$($GAId)&metrics=ga%3Avisits&start-date=$($startdate)&end-date=$($enddate)&max-results=50"
    if ($MyDebug){write-host $url}
    [xml]$results=$webclient.DownloadString($url)
    
    write-host ("$($Range)'s $($results.feed.entry.metric.name): $($results.feed.entry.metric.value)")
    }
    
    
    

  • PowerShell script to create a SystemUser in Microsoft CRM 2011

    I wanted to bulk create a bunch of users in CRM. PowerShell and the Microsoft CRM 2011 REST/OData endpoint make it easy. Here is a function to create a SystemUser via PowerShell

    FUNCTION JBMURPHY-CRM-CreateSystemUser {
    PARAM([string][ValidateSet("crmserver.company.com", "dev-crmserver.company.com")]$ServerName="crmserver.company.com",
    [string][ValidateSet("CRMOrganizationName")]$OrganizationName="CRMOrganizationName",
    [string]$BusinessUnitId="BusinessUnitGUID",
    [string]$SystemUserDomain="CRMSystemUserDomain",
    [string][parameter(Mandatory=$true)]$FirstName,
    [string][parameter(Mandatory=$true)]$LastName,
    [string][parameter(Mandatory=$true)]$UserName,[switch]$MyDebug
    )
    [string]$url="http://$ServerName/$($OrganizationName)/xrmservices/2011/OrganizationData.svc/SystemUserSet"
    
    $SystemUserInfo = @{
    DomainName="$($UserName)@$($SystemUserDomain)"
    FirstName=$FirstName
    LastName=$LastName
    BusinessUnitId=@{LogicalName="businessunit";Id=$BusinessUnitId}
    }
    $assembly = [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
    $json=new-object System.Web.Script.Serialization.JavaScriptSerializer
    $SystemUserInfoData=$json.Serialize($SystemUserInfo)
    
    $http_request = New-Object -ComObject Msxml2.XMLHTTP
    $http_request.open('POST', $url, $false)
    $http_request.setRequestHeader("Accept", "application/json")
    $http_request.setRequestHeader("Content-Type", "application/json; charset=utf-8")
    $results=$http_request.send($SystemUserInfoData)
    if ($MyDebug){
    $http_request.statusText
    $http_request
    }
    $SystemUserId=$($json.DeserializeObject($http_request.responseText)).d.SystemUserId
    return $SystemUserId
    }
    

  • PowerShell script to create a contact in Microsoft CRM 2011 via REST/ODATA

    Below is a PowerShell function to create a contact in CRM 2011. Hope it is helpful to some one.

    FUNCTION JBM-CRM-CreateContact {
    PARAM(
        [string][ValidateSet("crmserver.company.com", "dev-crmserver.company.com")]$ServerName="crmserver.company.com",
        [string][string][ValidateSet("CRMOrganizationName")]$OrganizationName="CRMOrganizationName",
        [string][parameter(Mandatory=$true)]$FirstName,
        [string][parameter(Mandatory=$true)]$LastName,
        [string]$MiddleName,[string]$Suffix,[string]$Email,[string]$JobTitle,
        [string]$Telephone,[string]$Description,[string]$ParentCustomerId,[string]$Address_Line1,[string]$Address_Line2,
        [string]$Address1_Country,[string]$Address1_PostalCode,[switch]$MyDebug
        )
    
    $ContactInfo = @{
    FirstName=$FirstName
    LastName=$LastName
    MiddleName=$MiddleName
    Suffix=$Suffix
    EMailAddress1=$Email
    NickName=$NickName
    JobTitle=$JobTitle
    Telephone1=$Telephone
    Address1_Line1=$Address_Line1
    Address1_Line2=$Address_Line2
    Address1_City=$Address1_City
    Address1_PostalCode=$Address1_PostalCode
    Address1_Country=$Address1_Country
    Description=$Description
    }
    if (!($ParentCustomerId -eq "")){
    $ContactInfo.Add("ParentCustomerId" , @{Id=$ParentCustomerId;LogicalName= "account"})
    }
    
    if ($MyDebug){
    $ParentCustomerId
    $ContactInfo
    }
    
    $assembly = [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
    $json=new-object System.Web.Script.Serialization.JavaScriptSerializer
    $ContactInfoData=$json.Serialize($ContactInfo)
    
    $url="http://$ServerName/$($OrganizationName)/xrmservices/2011/OrganizationData.svc/ContactSet"
     
    $http_request = New-Object -ComObject Msxml2.XMLHTTP
    $http_request.open('POST', $url, $false)
    $http_request.setRequestHeader("Accept", "application/json")
    $http_request.setRequestHeader("Content-Type", "application/json; charset=utf-8")
    $results=$http_request.send($ContactInfoData)
    if ($MyDebug){
    $http_request.statusText
    $http_request
    }
    $ContactId=$($json.DeserializeObject($http_request.responseText)).d.ContactId
    return $ContactId
    }
    
    

  • PowerShell script to add an activity via OData/REST

    I wanted to create some crm activities based on data in a spreadsheet. Looping thorough the csv file would be easy, the challenge came when I wanted to create new activities in Microsoft CRM 2011, specifically appointments. Below is a PowerShell function that I pieced together to create a new activity if you know GUIDs of the contacts for the regarding, required fields. This is a more fleshed out function compared to this

    FUNCTION JBM-CRM-CreateActivityODATA {
    PARAM([string][parameter(Mandatory=$true)][ValidateSet("Email", "PhoneCall", "Appointment")]$EntityType,
        [string][ValidateSet("crmserver.company.com", "dev-crmserver.company.com")]$ServerName="crmserver.company.com",
        [string][ValidateSet("CRMOrganizationName")]$OrganizationName="CRMOrganizationName",
        [string][parameter(Mandatory=$true)][ValidateScript({ $_ -match("^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$")})]$OwnerGUID,
        [string][ValidateScript({ $_ -match("^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$")})]$RegardingGUID,
        [ValidateScript({-not @( $_ | where {$_ -notmatch("^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$") }).Count})]$ReqiredGUIDs,
        [string]$Subject,[string]$Description,[datetime]$ScheduledStart,[datetime]$ScheduledEnd,[string]$Location
        )
    
    Function CreateActivityParty{
        PARAM($ActivityId,$ParticipationTypeMask,$EntityType,$GUIDs)
    
        foreach ($Id in $GUIDs){
        $activityParty = @{}
        write-host $Id
        $activityParty.Add("PartyId", @{Id= $Id;LogicalName= "contact"})
        $activityParty.Add("ActivityId", @{Id= $ActivityId;LogicalName= "$($EntityType.ToLower())"})
        $activityParty.Add("ParticipationTypeMask" , @{ Value=$ParticipationTypeMask })
        $json=new-object System.Web.Script.Serialization.JavaScriptSerializer
        $activityPartyData=$json.Serialize($activityParty)
        $activityPartyData
    
        $url="http://$ServerName/$($OrganizationName)/xrmservices/2011/OrganizationData.svc/ActivityPartySet"
     
        $http_request = New-Object -ComObject Msxml2.XMLHTTP
        $http_request.open('POST', $url, $false)
        $http_request.setRequestHeader("Accept", "application/json")
        $http_request.setRequestHeader("Content-Type", "application/json; charset=utf-8")
        $http_request.send($activityPartyData)
        $http_request.statusText
        $results=$http_request
        }
    }
    
    $assembly = [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
    $activityObject = @{
    ActivityTypeCode=$EntityType
    Subject=$Subject
    Description=$Description
    ScheduledStart=$($ScheduledStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))
    ScheduledEnd=$($ScheduledEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))
    Location=$Location
    RegardingObjectId=@{
    Id= $RegardingGUID
    LogicalName= "contact"
    }
    }
    
    $json = new-object System.Web.Script.Serialization.JavaScriptSerializer
    $activityData=$json.Serialize($activityObject)
    
    
    $url="http://$ServerName/$($OrganizationName)/xrmservices/2011/OrganizationData.svc/$($EntityType)Set"
     
    $http_request = New-Object -ComObject Msxml2.XMLHTTP
    $http_request.open('POST', $url, $false)
    $http_request.setRequestHeader("Accept", "application/json")
    $http_request.setRequestHeader("Content-Type", "application/json; charset=utf-8")
    $http_request.send($activityData)
    $results=$http_request
    $ActivityId=$($json.DeserializeObject($results.responseText)).d.ActivityId
    
    # Set Required Attendees
    CreateActivityParty -ActivityId $ActivityId -ParticipationTypeMask 5 -EntityType $EntityType -GUID $ReqiredGUIDs
    # Set Orgaizer
    CreateActivityParty -ActivityId $ActivityId -ParticipationTypeMask 7 -EntityType $EntityType -GUID $OwnerGUID
    }
    

  • PowerShell ValidateScript for and array of GUIDs as an argument

    Not sure if that title make sense, and I am not sure I understand this code, but it seems to work:

    Function TestArrayOfGUIDsArguemnt {
    PARAM(
    [ValidateScript({-not @( $_ | where {$_ -notmatch("^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$") }).Count})]$ArguemntToTest
    )
    write-host "Valid!"
    }
    
    Tests:
    
    TestArrayOfGUIDsArguemnt -ArguemntToTest "Jeff"
    TestArrayOfGUIDsArguemnt : Cannot validate argument on parameter 'ArguemntToTest'.
    
    TestArrayOfGUIDsArguemnt -ArguemntToTest "9e4c1911-f42a-42d9-af05-2a3df2823197"
    Valid!
    
    TestArrayOfGUIDsArguemnt -ArguemntToTest "9e4c1911-f42a-42d9-af05-2a3df2823197","557b8323-f630-40d3-b438-b2229806c47d"
    Valid!
    
    TestArrayOfGUIDsArguemnt -ArguemntToTest "9e4c1911-f42a-42d9-af05-2a3df2823197","557b8323-f630-40d3-b438-b2229806c47d","Jeff"
    TestArrayOfGUIDsArguemnt : Cannot validate argument on parameter 'ArguemntToTest'.
    
    Hope that helps some one?
    
    

    I got the idea from here


  • 5 PowerShell functions to create a SCCM “trickle install” – i.e. X at a time.

    If you look at this post, I describe a my idea of a SCCM trickle install – that is X number of machines at a time. Rather that have the install hit the whole collection at once, I wanted to hit just 20 a night. That way if there is an error, we can put the breaks on the deployment. We create dynamic collections that use a “NOT IN” SQL statement – this results in all the machines that are in the collection need the specific software. This script copies X at a time from that collection to new collection.

    In the previous post, I run a VBScript that loops through the first 10 (or X) number of machines in the collection and add them to a new collection that contains the assigned advertisement. The next night, the script runs again, and the next 10 (or X) are copied (since the source collection is dynamic, the machines from the night before are removed).

    I wanted to do the same thing, but I wanted to use PowerShell. First up, a function to find a Collection’s Id.

    FUNCTION JBM-SCCM-GetCollection {
    	Param([parameter(Mandatory = $true)]$CollectionName,
    	$SiteName="JBM",
    	$SCCMServer="sccmserver.domain.com")
    	$SCCMNameSpace="root\sms\site_$SiteName"
    	$QUERY="Select CollectionID from SMS_Collection WHERE Name = '$CollectionName'"
    	Return $(Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query $QUERY)
    }
    

    Next a function to find all the machines in a collection:

    FUNCTION JBM-SCCM-GetCollectionMembers{
    Param([parameter(Mandatory = $true)]$CollectionID,
    	$SiteName="JBM",
    	$SCCMServer="sccmserver.domain.com")
    	$SCCMNameSpace="root\sms\site_$SiteName"
    	$QUERY="SELECT Name FROM SMS_FullCollectionMembership WHERE CollectionID = '$CollectionID'"
    	Return $(Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query $QUERY)
    }
    

    Next a function to remove all machines in a collection (the ones that are directly added)

    FUNCTION JBM-SCCM-DeleteAllCollectionMembers{
    Param([parameter(Mandatory = $true)]$CollectionID,
    	$SiteName="JBM",
    	$SCCMServer="sccmserver.domain.com")
    	$SCCMNameSpace="root\sms\site_$SiteName"
        $Collection=[WMI]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_Collection.CollectionID='$CollectionID'"
    	ForEach ($Rule in  $Collection.CollectionRules ){
        $Collection.DeleteMembershipRule($Rule)
        }
    }
    

    Next, a function to add a machine to a Collection:

    FUNCTION JBM-SCCM-AddCollectionMember{
    Param([parameter(Mandatory = $true)]$CollectionID,
    	$SiteName="JBM",
    	$SCCMServer="sccmserver.domain.com",
        [parameter(Mandatory = $true)]$ComputerToAdd)
    	$SCCMNameSpace="root\sms\site_$SiteName"
    
        $computer = gwmi -computer $SCCMServer -namespace $SCCMNameSpace -Query "select * from SMS_R_System where NetBiosName='$ComputerToAdd'"
        $Collection=[WMI]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_Collection.CollectionID='$CollectionID'"
        $ruleClass = [wmiclass]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_CollectionRuleDirect"
        $newRule = $ruleClass.CreateInstance() 
        $newRule.RuleName = $ComputerToAdd 
        $newRule.ResourceClassName = "SMS_R_System" 
        $newRule.ResourceID = $computer.ResourceID 
        $null = $Collection.AddMembershipRule($newRule) 
    }
    

    Finally, a function to copy machines from one collection to another, using the functions above:

    FUNCTION JBM-SCCM-CopyCollectionMembers {
    Param([parameter(Mandatory = $true)]$SourceCollectionName,
        [parameter(Mandatory = $true)]$DestinationCollectionName,
        [parameter(Mandatory = $true)]$NumberToCopy)
    
        $SrcCollID=JBM-SCCM-GetCollection($SourceCollectionName)
        $DstCollID=JBM-SCCM-GetCollection($DestinationCollectionName)
        $SrcCollMembers=JBM-SCCM-GetCollectionMembers($SrcCollID.CollectionID)
        JBM-SCCM-DeleteAllCollectionMembers($DstCollID.CollectionID)
        foreach ($Computer in $($SrcCollMembers | select -first $NumberToCopy)){
        JBM-SCCM-AddCollectionMember -CollectionID $DstCollID.CollectionID -ComputerToAdd $Computer.Name
        }
    
    }
    

    The result – a trickle install.