none
Set Project Site URL via Workflow RRS feed

  • Question

  • Hi

    I try to create projects with a project site that has a different default language.

    On Premise I can set the Default Site Template language for project sites and then assign a german site template to an EPT. This option is not available online? If I assign the german template to the EPT the system says that this has the wrong language.

    What I can do is create a site manually and edit the site address in connected project sites to this URL.

    Can I do that programmatically, eg. in a workflow? Is there a CSOM alternative to the PSI UpdateProjectWorkspaceAddress call?

    Thanks a lot
    Christoph


    Christoph Muelder | Senior Consultant, MCTS, MCSE | SOLVIN information management GmbH, Germany

    Friday, May 20, 2016 1:10 PM

Answers

  • I looked for it for some time, and a colleague pointed me to the WssInterop PSI service that is still offered in 2016. The UpdateProjectWorkspaceAddress method previously hosted in the Project PSI service has moved there. Apart from that, it works as before.

    This page describes what it takes to retrieve the parameters needed for the call.

    Tuesday, August 30, 2016 11:22 AM
  • Okay, the problem is that the metadata publishing is no longer active for older services such as WssInterop, therefore the ..asmx?wsdl query will fail. So we have two URLs involved with the web request:

    1. the address ending on WssInterop.asmx is the service endpoint which is used to execute the web service call
    2. the address ending on WssInterop.wsdl is where the web service description can be retrieved

    Formerly, number 2 could be generated out of number 1 by appending "?wsdl", this is no longer true. However, the new-webserviceproxy method in PowerShell tries to do just that. So it cannot be used in this case.

    You may have to go the hard way, and create the SOAP message yourself, then use the Invoke-WebRequest method to access the service endpoint (address #1 shown above) without retrieving the wsdl first. This does work, however you won't enjoy any automatic SOAP message creation any longer, i.e. the XML that wraps the SOAP query needs to be put together manually, like so:

    $Body = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ReadWssSettings xmlns="http://schemas.microsoft.com/office/project/server/webservices/WssInterop/"/></s:Body></s:Envelope>'
    
    $head = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $head = @{}
    $head.Add("User-Agent","Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko/20100101 Firefox/12.0")
    $head.Add("SOAPAction","http://schemas.microsoft.com/office/project/server/webservices/WssInterop/ReadWssSettings")
    
    $content = Invoke-WebRequest `
        -UseDefaultCredentials `
        -Uri https://myserver.dom.local/PWA/_vti_bin/PSI/WssInterop.asmx `
        -Headers ($head) `
        -Method Post `
        -Body $Body `
        -ContentType text/xml
    
    echo $content.Content

    The User-Agent header is necessary because SharePoint will generate an internal server error if it is missing. The SOAPAction header as well as the message body will both need to mention the SOAP method that is being called. What you get back is the SOAP reply in XML where you can pick the desired values.

    Hope this works for you. It took me a considerable amount of time to get to this point :)

    Cheers,

    Johannes


    Monday, March 9, 2020 1:56 PM

All replies

  • I looked for it for some time, and a colleague pointed me to the WssInterop PSI service that is still offered in 2016. The UpdateProjectWorkspaceAddress method previously hosted in the Project PSI service has moved there. Apart from that, it works as before.

    This page describes what it takes to retrieve the parameters needed for the call.

    Tuesday, August 30, 2016 11:22 AM
  • Hi Johannes

    not sure, if I read your answer before and ran against a wall or not.....

    We just had the question on the table again and I would like to know, how you did it.

    new-webserviceproxy -uri ......../PSI/WSSInterop.asmx?wsdl does not work.

    There is a wssinterop.wsdl file in the system and it in fact contains the moved UpdateProjectWorkspaceAddress method. But I cannot find out, how to use it.

    Thanks

    Christoph


    Christoph Muelder | Senior Consultant, MCTS, MCSE | SOLVIN information management GmbH, Germany

    Friday, March 6, 2020 11:27 AM
  • Hi Christoph,


    well, are we still talking Project Server 2016? The following code was verified to work in a 2016 environment but I don't know if it will work in Project Server 2013 or 2019 though.

    private void UnlinkProjectWssSite(Guid projUid)
    {
        var data = this.GetWssData(projUid);
        if (data == null) return;
        var currentWorkspace = data.PROJECT_WORKSPACE_URL;
        var wssSvc = this.GetWssInteropSvc2016();
        wssSvc.UpdateProjectWorkspaceAddress(projUid, string.Empty, Guid.Empty);
    }
    
    private void LinkProjectWssSite(Guid projUid, string wssUrl, Guid wssServerGuid)
    {
        var jobUid = System.Guid.NewGuid();
        var dsCurrentWssInfo = this.GetWssInteropSvc2016().ReadWssSettings();
        var adminRow = dsCurrentWssInfo.WssAdmin[0];
        var siteCollection = string.Empty;
        if (!adminRow.IsWADMIN_DEFAULT_SITE_COLLECTIONNull()) siteCollection = adminRow.WADMIN_DEFAULT_SITE_COLLECTION;
        var tempWssUrl = wssUrl.Substring(wssUrl.LastIndexOf('/'));
        this.GetWssInteropSvc2016().UpdateProjectWorkspaceAddress(projUid, siteCollection + tempWssUrl, wssServerGuid);
    }

    The GetWssInteropSvc2016() method just returns the service object which in this case is done in an abstraction layer. Should work with any other way of getting this service.

    Which brings us to a possible solution. You mentioned you are using this address:

    new-webserviceproxy -uri ......../PSI/WSSInterop.asmx?wsdl 

    Have you tried this alternative instead?

    new-webserviceproxy -uri ......../PSI/WSSInterop.wsdl 

    Hope this helps...

    Cheers,

    Johannes

    Monday, March 9, 2020 9:59 AM
  • Hi

    Thanks. Yes, the alternate way brings me much further.

    

    I do not think that the URL value is correct. At least when I try to use the UpdateProjectWorkspaceAddress method, it tries to connect to microsoft.com......

    Using Project Server 2016

    Thanks and kind regards

    Christoph


    Christoph Muelder | Senior Consultant, MCTS, MCSE | SOLVIN information management GmbH, Germany

    Monday, March 9, 2020 10:27 AM
  • Okay, the problem is that the metadata publishing is no longer active for older services such as WssInterop, therefore the ..asmx?wsdl query will fail. So we have two URLs involved with the web request:

    1. the address ending on WssInterop.asmx is the service endpoint which is used to execute the web service call
    2. the address ending on WssInterop.wsdl is where the web service description can be retrieved

    Formerly, number 2 could be generated out of number 1 by appending "?wsdl", this is no longer true. However, the new-webserviceproxy method in PowerShell tries to do just that. So it cannot be used in this case.

    You may have to go the hard way, and create the SOAP message yourself, then use the Invoke-WebRequest method to access the service endpoint (address #1 shown above) without retrieving the wsdl first. This does work, however you won't enjoy any automatic SOAP message creation any longer, i.e. the XML that wraps the SOAP query needs to be put together manually, like so:

    $Body = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ReadWssSettings xmlns="http://schemas.microsoft.com/office/project/server/webservices/WssInterop/"/></s:Body></s:Envelope>'
    
    $head = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $head = @{}
    $head.Add("User-Agent","Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko/20100101 Firefox/12.0")
    $head.Add("SOAPAction","http://schemas.microsoft.com/office/project/server/webservices/WssInterop/ReadWssSettings")
    
    $content = Invoke-WebRequest `
        -UseDefaultCredentials `
        -Uri https://myserver.dom.local/PWA/_vti_bin/PSI/WssInterop.asmx `
        -Headers ($head) `
        -Method Post `
        -Body $Body `
        -ContentType text/xml
    
    echo $content.Content

    The User-Agent header is necessary because SharePoint will generate an internal server error if it is missing. The SOAPAction header as well as the message body will both need to mention the SOAP method that is being called. What you get back is the SOAP reply in XML where you can pick the desired values.

    Hope this works for you. It took me a considerable amount of time to get to this point :)

    Cheers,

    Johannes


    Monday, March 9, 2020 1:56 PM